]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/sys_persona.c
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/param.h>
29 #include <sys/kernel.h>
30 #include <sys/kernel_types.h>
31 #include <sys/sysproto.h>
33 #include <sys/kauth.h>
34 #include <sys/malloc.h>
35 #include <sys/persona.h>
38 #include <libkern/libkern.h>
40 static int kpersona_copyin(user_addr_t infop
, struct kpersona_info
*kinfo
)
45 error
= copyin(infop
, &info_v
, sizeof(info_v
));
49 /* only support a single version of the struct for now */
50 if (info_v
!= PERSONA_INFO_V1
)
53 error
= copyin(infop
, kinfo
, sizeof(*kinfo
));
55 /* enforce NULL termination on strings */
56 kinfo
->persona_name
[MAXLOGNAME
] = 0;
61 static int kpersona_copyout(struct kpersona_info
*kinfo
, user_addr_t infop
)
66 error
= copyin(infop
, &info_v
, sizeof(info_v
));
70 /* only support a single version of the struct for now */
71 /* TODO: in the future compare info_v to kinfo->persona_info_version */
72 if (info_v
!= PERSONA_INFO_V1
)
75 error
= copyout(kinfo
, infop
, sizeof(*kinfo
));
80 static int kpersona_alloc_syscall(user_addr_t infop
, user_addr_t idp
)
83 struct kpersona_info kinfo
;
84 struct persona
*persona
;
85 uid_t id
= PERSONA_ID_NONE
;
89 * TODO: rdar://problem/19981151
90 * Add entitlement check!
92 if (!kauth_cred_issuser(kauth_cred_get()))
95 error
= kpersona_copyin(infop
, &kinfo
);
99 login
= kinfo
.persona_name
[0] ? kinfo
.persona_name
: NULL
;
100 if (kinfo
.persona_id
!= PERSONA_ID_NONE
&& kinfo
.persona_id
!= (uid_t
)0)
101 id
= kinfo
.persona_id
;
104 persona
= persona_alloc(id
, login
, kinfo
.persona_type
, &error
);
108 if (kinfo
.persona_gid
) {
109 error
= persona_set_gid(persona
, kinfo
.persona_gid
);
114 if (kinfo
.persona_ngroups
> 0) {
115 /* force gmuid 0 to *opt-out* of memberd */
116 if (kinfo
.persona_gmuid
== 0)
117 kinfo
.persona_gmuid
= KAUTH_UID_NONE
;
119 error
= persona_set_groups(persona
, kinfo
.persona_groups
,
120 kinfo
.persona_ngroups
,
121 kinfo
.persona_gmuid
);
126 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
129 error
= kpersona_copyout(&kinfo
, infop
);
132 * On success, we have a persona structure in the global list with a
133 * single reference count on it. The corresponding _dealloc() call
134 * will release this reference.
139 printf("%s: ERROR:%d\n", __func__
, error
);
141 persona_put(persona
);
145 static int kpersona_dealloc_syscall(user_addr_t idp
)
149 struct persona
*persona
;
151 if (!kauth_cred_issuser(kauth_cred_get()))
154 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
158 persona
= persona_lookup(persona_id
);
162 /* invalidate the persona (deny subsequent spawn/fork) */
163 error
= persona_invalidate(persona
);
165 /* one reference from the _lookup() */
166 persona_put(persona
);
168 /* one reference from the _alloc() */
170 persona_put(persona
);
175 static int kpersona_get_syscall(user_addr_t idp
)
178 struct persona
*persona
= current_persona_get();
183 error
= copyout(&persona
->pna_id
, idp
, sizeof(persona
->pna_id
));
184 persona_put(persona
);
189 static int kpersona_info_syscall(user_addr_t idp
, user_addr_t infop
)
193 struct persona
*persona
;
194 struct kpersona_info kinfo
;
196 error
= copyin(idp
, &persona_id
, sizeof(persona_id
));
201 * TODO: rdar://problem/19981151
202 * Add entitlement check!
205 persona
= persona_lookup(persona_id
);
209 persona_dbg("FOUND: persona:%p, id:%d, gid:%d, login:\"%s\"",
210 persona
, persona
->pna_id
, persona_get_gid(persona
),
213 memset(&kinfo
, 0, sizeof(kinfo
));
214 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
215 kinfo
.persona_id
= persona
->pna_id
;
216 kinfo
.persona_type
= persona
->pna_type
;
217 kinfo
.persona_gid
= persona_get_gid(persona
);
218 unsigned ngroups
= 0;
219 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
220 kinfo
.persona_ngroups
= ngroups
;
221 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
224 * NULL termination is assured b/c persona_name is
225 * exactly MAXLOGNAME + 1 bytes (and has been memset to 0)
227 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
229 persona_put(persona
);
231 error
= kpersona_copyout(&kinfo
, infop
);
236 static int kpersona_pidinfo_syscall(user_addr_t idp
, user_addr_t infop
)
240 struct persona
*persona
;
241 struct kpersona_info kinfo
;
243 error
= copyin(idp
, &pid
, sizeof(pid
));
247 if (!kauth_cred_issuser(kauth_cred_get())
248 && (pid
!= current_proc()->p_pid
))
251 persona
= persona_proc_get(pid
);
255 memset(&kinfo
, 0, sizeof(kinfo
));
256 kinfo
.persona_info_version
= PERSONA_INFO_V1
;
257 kinfo
.persona_id
= persona
->pna_id
;
258 kinfo
.persona_type
= persona
->pna_type
;
259 kinfo
.persona_gid
= persona_get_gid(persona
);
260 unsigned ngroups
= 0;
261 persona_get_groups(persona
, &ngroups
, kinfo
.persona_groups
, NGROUPS
);
262 kinfo
.persona_ngroups
= ngroups
;
263 kinfo
.persona_gmuid
= persona_get_gmuid(persona
);
265 strncpy(kinfo
.persona_name
, persona
->pna_login
, MAXLOGNAME
);
267 persona_put(persona
);
269 error
= kpersona_copyout(&kinfo
, infop
);
274 static int kpersona_find_syscall(user_addr_t infop
, user_addr_t idp
, user_addr_t idlenp
)
277 struct kpersona_info kinfo
;
279 size_t u_idlen
, k_idlen
= 0;
280 struct persona
**persona
= NULL
;
282 error
= copyin(idlenp
, &u_idlen
, sizeof(u_idlen
));
286 if (u_idlen
> g_max_personas
)
287 u_idlen
= g_max_personas
;
289 error
= kpersona_copyin(infop
, &kinfo
);
293 login
= kinfo
.persona_name
[0] ? kinfo
.persona_name
: NULL
;
296 MALLOC(persona
, struct persona
**, sizeof(*persona
) * u_idlen
,
297 M_TEMP
, M_WAITOK
|M_ZERO
);
305 error
= persona_find(login
, kinfo
.persona_id
, persona
, &k_idlen
);
309 /* copyout all the IDs of each persona we found */
310 for (size_t i
= 0; i
< k_idlen
; i
++) {
313 error
= copyout(&persona
[i
]->pna_id
,
314 idp
+ (i
* sizeof(persona
[i
]->pna_id
)),
315 sizeof(persona
[i
]->pna_id
));
322 for (size_t i
= 0; i
< u_idlen
; i
++)
323 persona_put(persona
[i
]);
324 FREE(persona
, M_TEMP
);
327 (void)copyout(&k_idlen
, idlenp
, sizeof(u_idlen
));
334 * Syscall entry point / demux.
336 int persona(__unused proc_t p
, struct persona_args
*pargs
, __unused
int32_t *retval
)
339 uint32_t op
= pargs
->operation
;
340 /* uint32_t flags = pargs->flags; */
341 user_addr_t infop
= pargs
->info
;
342 user_addr_t idp
= pargs
->id
;
345 case PERSONA_OP_ALLOC
:
346 error
= kpersona_alloc_syscall(infop
, idp
);
348 case PERSONA_OP_DEALLOC
:
349 error
= kpersona_dealloc_syscall(idp
);
352 error
= kpersona_get_syscall(idp
);
354 case PERSONA_OP_INFO
:
355 error
= kpersona_info_syscall(idp
, infop
);
357 case PERSONA_OP_PIDINFO
:
358 error
= kpersona_pidinfo_syscall(idp
, infop
);
360 case PERSONA_OP_FIND
:
361 error
= kpersona_find_syscall(infop
, idp
, pargs
->idlen
);