1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
4 #include "authd_private.h"
8 #include "authutilities.h"
11 #include <CommonCrypto/CommonRandomSPI.h>
12 #include <Security/Authorization.h>
13 #include <Security/SecBase.h>
18 static Boolean
AuthTokenEqualCallBack(const void *value1
, const void *value2
)
20 return (*(uint64_t*)value1
) == (*(uint64_t*)value2
);
23 static CFHashCode
AuthTokenHashCallBack(const void *value
)
26 // AuthorizationBlob* blob = (AuthorizationBlob*)value;
27 // hash = blob->data[1];
29 // hash |= blob->data[0];
31 //quick 64 bit aligned version
32 return *((CFHashCode
*)((AuthorizationBlob
*)value
)->data
);
35 const CFDictionaryKeyCallBacks kAuthTokenKeyCallBacks
= {
39 .copyDescription
= NULL
,
40 .equal
= &AuthTokenEqualCallBack
,
41 .hash
= &AuthTokenHashCallBack
44 struct _auth_token_s
{
45 __AUTH_BASE_STRUCT_HEADER__
;
47 AuthorizationBlob blob
;
48 auth_token_state_t state
;
49 audit_info_s auditInfo
;
50 dispatch_queue_t dispatch_queue
;
52 CFMutableSetRef processes
;
55 process_t creator
; // weak reference, used for entitlement checking
56 mach_port_t creator_bootstrap_port
;
60 CFMutableSetRef credentials
;
61 CFMutableSetRef authorized_rights
;
63 CFMutableDataRef encryption_key
;
65 bool least_privileged
;
67 bool firstPartySigned
;
72 credential_t credential
;
76 _auth_token_finalize(CFTypeRef value
)
78 auth_token_t auth
= (auth_token_t
)value
;
79 os_log_debug(AUTHD_LOG
, "authtoken: finalizing");
81 dispatch_barrier_sync(auth
->dispatch_queue
, ^{});
83 dispatch_release(auth
->dispatch_queue
);
84 CFReleaseNull(auth
->session
);
85 CFReleaseNull(auth
->processes
);
86 CFReleaseNull(auth
->context
);
87 CFReleaseNull(auth
->credentials
);
88 CFReleaseNull(auth
->authorized_rights
);
89 free_safe(auth
->code_url
);
90 CFReleaseNull(auth
->credential
);
91 CFReleaseNull(auth
->encryption_key
);
93 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
94 mach_port_deallocate(mach_task_self(), auth
->creator_bootstrap_port
);
95 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
100 _auth_token_equal(CFTypeRef value1
, CFTypeRef value2
)
102 auth_token_t auth1
= (auth_token_t
)value1
;
103 auth_token_t auth2
= (auth_token_t
)value2
;
105 return memcmp(&auth1
->blob
, &auth2
->blob
, sizeof(AuthorizationBlob
)) == 0;
109 _auth_token_copy_description(CFTypeRef value
)
111 auth_token_t auth
= (auth_token_t
)value
;
112 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("auth_token: uid=%i, pid=%i, processes=%li least_privileged=%i"),
113 auth
->auditInfo
.euid
, auth
->auditInfo
.pid
, CFSetGetCount(auth
->processes
), auth
->least_privileged
);
117 _auth_token_hash(CFTypeRef value
)
119 auth_token_t auth
= (auth_token_t
)value
;
120 return *(CFHashCode
*)&auth
->blob
;
123 AUTH_TYPE_INSTANCE(auth_token
,
126 .finalize
= _auth_token_finalize
,
127 .equal
= _auth_token_equal
,
128 .hash
= _auth_token_hash
,
129 .copyFormattingDesc
= NULL
,
130 .copyDebugDesc
= _auth_token_copy_description
133 static CFTypeID
auth_token_get_type_id() {
134 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
135 static dispatch_once_t onceToken
;
137 dispatch_once(&onceToken
, ^{
138 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_token
);
145 _auth_token_create(const audit_info_s
* auditInfo
, bool operateAsLeastPrivileged
)
148 __Check_Compile_Time(sizeof(CFHashCode
) == sizeof(AuthorizationBlob
));
151 auth_token_t auth
= (auth_token_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_token_get_type_id(), AUTH_CLASS_SIZE(auth_token
), NULL
);
152 require(auth
!= NULL
, done
);
154 if (CCRandomCopyBytes(kCCRandomDefault
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != kCCSuccess
) {
155 os_log_error(AUTHD_LOG
, "authtoken: failed to generate blob (PID %d)", auditInfo
->pid
);
160 auth
->context
= auth_items_create();
161 auth
->auditInfo
= *auditInfo
;
162 auth
->least_privileged
= operateAsLeastPrivileged
;
164 auth
->dispatch_queue
= dispatch_queue_create(NULL
, DISPATCH_QUEUE_SERIAL
);
165 check(auth
->dispatch_queue
!= NULL
);
167 auth
->credentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
168 auth
->authorized_rights
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
169 auth
->processes
= CFSetCreateMutable(kCFAllocatorDefault
, 0, NULL
);
170 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
172 if (sandbox_check_by_audit_token(auth
->auditInfo
.opaqueToken
, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT
) != 0)
173 auth
->sandboxed
= true;
175 auth
->sandboxed
= false;
177 size_t key_length
= kCCKeySizeAES256
;
178 auth
->encryption_key
= CFDataCreateMutable(kCFAllocatorDefault
, key_length
);
179 if (auth
->encryption_key
) {
180 int rv
= CCRandomCopyBytes(kCCRandomDefault
, CFDataGetMutableBytePtr(auth
->encryption_key
), key_length
);
181 if (rv
!= kCCSuccess
) {
182 CFReleaseNull(auth
->encryption_key
)
184 CFDataSetLength(auth
->encryption_key
, key_length
);
188 CFHashCode code
= AuthTokenHashCallBack(&auth
->blob
);
189 if (memcmp(&code
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != 0) {
190 os_log_debug(AUTHD_LOG
, "authtoken[%i]: blob = %x%01x", auth
->auditInfo
.pid
, auth
->blob
.data
[1], auth
->blob
.data
[0]);
191 os_log_debug(AUTHD_LOG
, "authtoken[%i]: hash = %lx", auth
->auditInfo
.pid
, code
);
201 auth_token_create(process_t proc
, bool operateAsLeastPrivileged
)
203 auth_token_t auth
= NULL
;
204 require(proc
!= NULL
, done
);
206 auth
= _auth_token_create(process_get_audit_info(proc
), operateAsLeastPrivileged
);
207 require(auth
!= NULL
, done
);
209 auth
->creator
= proc
;
210 auth
->session
= (session_t
)CFRetain(process_get_session(proc
));
211 auth
->code_url
= _copy_string(process_get_code_url(proc
));
212 auth
->appleSigned
= process_apple_signed(proc
);
213 auth
->creator_bootstrap_port
= process_get_bootstrap(proc
);
214 // This line grabs a reference to the send right to the bootstrap (our right to send to the bootstrap)
215 // This makes it critical to use the same call in reverse as we are only getting a ref to one right,
216 // but deallocate will free a ref to all 5 rights.
217 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
218 kern_return_t error_code
= mach_port_mod_refs(mach_task_self(), auth
->creator_bootstrap_port
, MACH_PORT_RIGHT_SEND
, 1);
219 if (error_code
!= KERN_SUCCESS
) {
220 // If no reference to the mach port right can be obtained, we don't hold the copy, so mark it NULL again!
221 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
225 os_log_debug(AUTHD_LOG
, "authtoken: created for PID %d", auth
->auditInfo
.pid
);
232 auth_token_get_sandboxed(auth_token_t auth
)
234 return auth
->sandboxed
;
238 auth_token_get_code_url(auth_token_t auth
)
240 return auth
->code_url
;
244 auth_token_get_key(auth_token_t auth
)
250 auth_token_get_context(auth_token_t auth
)
252 return auth
->context
;
256 auth_token_least_privileged(auth_token_t auth
)
258 return auth
->least_privileged
;
262 auth_token_get_uid(auth_token_t auth
)
264 assert(auth
); // marked non-null
265 return auth
->auditInfo
.euid
;
269 auth_token_get_pid(auth_token_t auth
)
271 assert(auth
); // marked non-null
272 return auth
->auditInfo
.pid
;
276 auth_token_get_session(auth_token_t auth
)
278 return auth
->session
;
281 const AuthorizationBlob
*
282 auth_token_get_blob(auth_token_t auth
)
288 auth_token_get_audit_info(auth_token_t auth
)
290 return &auth
->auditInfo
;
294 auth_token_get_creator_bootstrap(auth_token_t auth
)
296 return auth
->creator_bootstrap_port
;
300 auth_token_add_process(auth_token_t auth
, process_t proc
)
302 __block CFIndex count
= 0;
303 dispatch_sync(auth
->dispatch_queue
, ^{
304 CFSetAddValue(auth
->processes
, proc
);
305 count
= CFSetGetCount(auth
->processes
);
311 auth_token_remove_process(auth_token_t auth
, process_t proc
)
313 __block CFIndex count
= 0;
314 dispatch_sync(auth
->dispatch_queue
, ^{
315 if (auth
->creator
== proc
) {
316 auth
->creator
= NULL
;
318 CFSetRemoveValue(auth
->processes
, proc
);
319 count
= CFSetGetCount(auth
->processes
);
325 auth_token_get_process_count(auth_token_t auth
)
327 __block CFIndex count
= 0;
328 dispatch_sync(auth
->dispatch_queue
, ^{
329 count
= CFSetGetCount(auth
->processes
);
335 auth_token_set_credential(auth_token_t auth
, credential_t cred
)
337 dispatch_sync(auth
->dispatch_queue
, ^{
338 CFSetSetValue(auth
->credentials
, cred
);
343 auth_token_credentials_iterate(auth_token_t auth
, credential_iterator_t iter
)
345 __block
bool result
= false;
347 dispatch_sync(auth
->dispatch_queue
, ^{
348 CFIndex count
= CFSetGetCount(auth
->credentials
);
349 if (count
> 128) { // <rdar://problem/38179345> Variable Length Arrays; AuthD
350 // auth_token usually contains 0 or 1 credential
353 CFTypeRef values
[count
];
354 CFSetGetValues(auth
->credentials
, values
);
355 for (CFIndex i
= 0; i
< count
; i
++) {
356 credential_t cred
= (credential_t
)values
[i
];
368 auth_token_set_right(auth_token_t auth
, credential_t right
)
370 dispatch_sync(auth
->dispatch_queue
, ^{
371 CFSetSetValue(auth
->authorized_rights
, right
);
376 auth_token_copy_entitlement_value(auth_token_t auth
, const char * entitlement
)
378 __block CFTypeRef value
= NULL
;
379 dispatch_sync(auth
->dispatch_queue
, ^{
381 value
= process_copy_entitlement_value(auth
->creator
, entitlement
);
389 auth_token_has_entitlement(auth_token_t auth
, const char * entitlement
)
391 __block
bool entitled
= false;
393 dispatch_sync(auth
->dispatch_queue
, ^{
395 entitled
= process_has_entitlement(auth
->creator
, entitlement
);
398 os_log_debug(AUTHD_LOG
, "authtoken: PID %d is%{public}s entitled for %{public}s", auth
->auditInfo
.pid
, entitled
? "":" not", entitlement
);
404 auth_token_has_entitlement_for_right(auth_token_t auth
, const char * right
)
406 __block
bool entitled
= false;
408 dispatch_sync(auth
->dispatch_queue
, ^{
410 entitled
= process_has_entitlement_for_right(auth
->creator
, right
);
413 os_log_debug(AUTHD_LOG
, "authtoken: PID %d is%{public}s entitled for right %{public}s", auth
->auditInfo
.pid
, entitled
? "":" not", right
);
419 auth_token_get_credential(auth_token_t auth
)
421 dispatch_sync(auth
->dispatch_queue
, ^{
422 if (auth
->credential
== NULL
) {
423 auth
->credential
= credential_create(auth
->auditInfo
.euid
);
427 return auth
->credential
;
431 auth_token_apple_signed(auth_token_t auth
)
433 return auth
->appleSigned
;
436 bool auth_token_is_creator(auth_token_t auth
, process_t proc
)
438 assert(proc
); // marked non-null
439 __block
bool creator
= false;
440 dispatch_sync(auth
->dispatch_queue
, ^{
441 if (auth
->creator
== proc
) {
448 void auth_token_set_state(auth_token_t auth
, auth_token_state_t state
)
450 auth
->state
|= state
;
453 void auth_token_clear_state(auth_token_t auth
, auth_token_state_t state
)
455 auth
->state
&= ~state
;
458 auth_token_state_t
auth_token_get_state(auth_token_t auth
)
463 bool auth_token_check_state(auth_token_t auth
, auth_token_state_t state
)
466 return (auth
->state
& state
) != 0;
468 return auth
->state
== 0;
472 CFDataRef
auth_token_get_encryption_key(auth_token_t auth
)
474 return auth
->encryption_key
;