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>
16 #include <security_utilities/simulatecrash_assert.h>
20 static Boolean
AuthTokenEqualCallBack(const void *value1
, const void *value2
)
22 return (*(uint64_t*)value1
) == (*(uint64_t*)value2
);
25 static CFHashCode
AuthTokenHashCallBack(const void *value
)
28 // AuthorizationBlob* blob = (AuthorizationBlob*)value;
29 // hash = blob->data[1];
31 // hash |= blob->data[0];
33 //quick 64 bit aligned version
34 return *((CFHashCode
*)((AuthorizationBlob
*)value
)->data
);
37 const CFDictionaryKeyCallBacks kAuthTokenKeyCallBacks
= {
41 .copyDescription
= NULL
,
42 .equal
= &AuthTokenEqualCallBack
,
43 .hash
= &AuthTokenHashCallBack
46 struct _auth_token_s
{
47 __AUTH_BASE_STRUCT_HEADER__
;
49 AuthorizationBlob blob
;
50 auth_token_state_t state
;
51 audit_info_s auditInfo
;
52 dispatch_queue_t dispatch_queue
;
54 CFMutableSetRef processes
;
57 process_t creator
; // weak reference, used for entitlement checking
58 mach_port_t creator_bootstrap_port
;
62 CFMutableSetRef credentials
;
63 CFMutableSetRef authorized_rights
;
65 CFMutableDataRef encryption_key
;
67 bool least_privileged
;
69 bool firstPartySigned
;
74 credential_t credential
;
78 _auth_token_finalize(CFTypeRef value
)
80 auth_token_t auth
= (auth_token_t
)value
;
81 os_log_debug(AUTHD_LOG
, "authtoken: finalizing");
83 dispatch_barrier_sync(auth
->dispatch_queue
, ^{});
85 dispatch_release(auth
->dispatch_queue
);
86 CFReleaseNull(auth
->session
);
87 CFReleaseNull(auth
->processes
);
88 CFReleaseNull(auth
->context
);
89 CFReleaseNull(auth
->credentials
);
90 CFReleaseNull(auth
->authorized_rights
);
91 free_safe(auth
->code_url
);
92 CFReleaseNull(auth
->credential
);
93 CFReleaseNull(auth
->encryption_key
);
95 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
96 mach_port_deallocate(mach_task_self(), auth
->creator_bootstrap_port
);
97 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
102 _auth_token_equal(CFTypeRef value1
, CFTypeRef value2
)
104 auth_token_t auth1
= (auth_token_t
)value1
;
105 auth_token_t auth2
= (auth_token_t
)value2
;
107 return memcmp(&auth1
->blob
, &auth2
->blob
, sizeof(AuthorizationBlob
)) == 0;
111 _auth_token_copy_description(CFTypeRef value
)
113 auth_token_t auth
= (auth_token_t
)value
;
114 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("auth_token: uid=%i, pid=%i, processes=%li least_privileged=%i"),
115 auth
->auditInfo
.euid
, auth
->auditInfo
.pid
, CFSetGetCount(auth
->processes
), auth
->least_privileged
);
119 _auth_token_hash(CFTypeRef value
)
121 auth_token_t auth
= (auth_token_t
)value
;
122 return *(CFHashCode
*)&auth
->blob
;
125 AUTH_TYPE_INSTANCE(auth_token
,
128 .finalize
= _auth_token_finalize
,
129 .equal
= _auth_token_equal
,
130 .hash
= _auth_token_hash
,
131 .copyFormattingDesc
= NULL
,
132 .copyDebugDesc
= _auth_token_copy_description
135 static CFTypeID
auth_token_get_type_id() {
136 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
137 static dispatch_once_t onceToken
;
139 dispatch_once(&onceToken
, ^{
140 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_token
);
147 _auth_token_create(const audit_info_s
* auditInfo
, bool operateAsLeastPrivileged
)
150 __Check_Compile_Time(sizeof(CFHashCode
) == sizeof(AuthorizationBlob
));
153 auth_token_t auth
= (auth_token_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_token_get_type_id(), AUTH_CLASS_SIZE(auth_token
), NULL
);
154 require(auth
!= NULL
, done
);
156 if (CCRandomCopyBytes(kCCRandomDefault
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != kCCSuccess
) {
157 os_log_error(AUTHD_LOG
, "authtoken: failed to generate blob (PID %d)", auditInfo
->pid
);
162 auth
->context
= auth_items_create();
163 auth
->auditInfo
= *auditInfo
;
164 auth
->least_privileged
= operateAsLeastPrivileged
;
166 auth
->dispatch_queue
= dispatch_queue_create(NULL
, DISPATCH_QUEUE_SERIAL
);
167 check(auth
->dispatch_queue
!= NULL
);
169 auth
->credentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
170 auth
->authorized_rights
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
171 auth
->processes
= CFSetCreateMutable(kCFAllocatorDefault
, 0, NULL
);
172 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
174 if (sandbox_check_by_audit_token(auth
->auditInfo
.opaqueToken
, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT
) != 0)
175 auth
->sandboxed
= true;
177 auth
->sandboxed
= false;
179 size_t key_length
= kCCKeySizeAES256
;
180 auth
->encryption_key
= CFDataCreateMutable(kCFAllocatorDefault
, key_length
);
181 if (auth
->encryption_key
) {
182 int rv
= CCRandomCopyBytes(kCCRandomDefault
, CFDataGetMutableBytePtr(auth
->encryption_key
), key_length
);
183 if (rv
!= kCCSuccess
) {
184 CFReleaseNull(auth
->encryption_key
)
186 CFDataSetLength(auth
->encryption_key
, key_length
);
190 CFHashCode code
= AuthTokenHashCallBack(&auth
->blob
);
191 if (memcmp(&code
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != 0) {
192 os_log_debug(AUTHD_LOG
, "authtoken[%i]: blob = %x%01x", auth
->auditInfo
.pid
, auth
->blob
.data
[1], auth
->blob
.data
[0]);
193 os_log_debug(AUTHD_LOG
, "authtoken[%i]: hash = %lx", auth
->auditInfo
.pid
, code
);
203 auth_token_create(process_t proc
, bool operateAsLeastPrivileged
)
205 auth_token_t auth
= NULL
;
206 require(proc
!= NULL
, done
);
208 auth
= _auth_token_create(process_get_audit_info(proc
), operateAsLeastPrivileged
);
209 require(auth
!= NULL
, done
);
211 auth
->creator
= proc
;
212 auth
->session
= (session_t
)CFRetain(process_get_session(proc
));
213 auth
->code_url
= _copy_string(process_get_code_url(proc
));
214 auth
->appleSigned
= process_apple_signed(proc
);
215 auth
->creator_bootstrap_port
= process_get_bootstrap(proc
);
216 // This line grabs a reference to the send right to the bootstrap (our right to send to the bootstrap)
217 // This makes it critical to use the same call in reverse as we are only getting a ref to one right,
218 // but deallocate will free a ref to all 5 rights.
219 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
220 kern_return_t error_code
= mach_port_mod_refs(mach_task_self(), auth
->creator_bootstrap_port
, MACH_PORT_RIGHT_SEND
, 1);
221 if (error_code
!= KERN_SUCCESS
) {
222 // If no reference to the mach port right can be obtained, we don't hold the copy, so mark it NULL again!
223 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
227 os_log_debug(AUTHD_LOG
, "authtoken: created for PID %d", auth
->auditInfo
.pid
);
234 auth_token_get_sandboxed(auth_token_t auth
)
236 return auth
->sandboxed
;
240 auth_token_get_code_url(auth_token_t auth
)
242 return auth
->code_url
;
246 auth_token_get_key(auth_token_t auth
)
252 auth_token_get_context(auth_token_t auth
)
254 return auth
->context
;
258 auth_token_least_privileged(auth_token_t auth
)
260 return auth
->least_privileged
;
264 auth_token_get_uid(auth_token_t auth
)
266 assert(auth
); // marked non-null
267 return auth
->auditInfo
.euid
;
271 auth_token_get_pid(auth_token_t auth
)
273 assert(auth
); // marked non-null
274 return auth
->auditInfo
.pid
;
278 auth_token_get_session(auth_token_t auth
)
280 return auth
->session
;
283 const AuthorizationBlob
*
284 auth_token_get_blob(auth_token_t auth
)
290 auth_token_get_audit_info(auth_token_t auth
)
292 return &auth
->auditInfo
;
296 auth_token_get_creator_bootstrap(auth_token_t auth
)
298 return auth
->creator_bootstrap_port
;
302 auth_token_add_process(auth_token_t auth
, process_t proc
)
304 __block CFIndex count
= 0;
305 dispatch_sync(auth
->dispatch_queue
, ^{
306 CFSetAddValue(auth
->processes
, proc
);
307 count
= CFSetGetCount(auth
->processes
);
313 auth_token_remove_process(auth_token_t auth
, process_t proc
)
315 __block CFIndex count
= 0;
316 dispatch_sync(auth
->dispatch_queue
, ^{
317 if (auth
->creator
== proc
) {
318 auth
->creator
= NULL
;
320 CFSetRemoveValue(auth
->processes
, proc
);
321 count
= CFSetGetCount(auth
->processes
);
327 auth_token_get_process_count(auth_token_t auth
)
329 __block CFIndex count
= 0;
330 dispatch_sync(auth
->dispatch_queue
, ^{
331 count
= CFSetGetCount(auth
->processes
);
337 auth_token_set_credential(auth_token_t auth
, credential_t cred
)
339 dispatch_sync(auth
->dispatch_queue
, ^{
340 CFSetSetValue(auth
->credentials
, cred
);
345 auth_token_credentials_iterate(auth_token_t auth
, credential_iterator_t iter
)
347 __block
bool result
= false;
349 dispatch_sync(auth
->dispatch_queue
, ^{
350 CFIndex count
= CFSetGetCount(auth
->credentials
);
351 if (count
> 128) { // <rdar://problem/38179345> Variable Length Arrays; AuthD
352 // auth_token usually contains 0 or 1 credential
355 CFTypeRef values
[count
];
356 CFSetGetValues(auth
->credentials
, values
);
357 for (CFIndex i
= 0; i
< count
; i
++) {
358 credential_t cred
= (credential_t
)values
[i
];
370 auth_token_set_right(auth_token_t auth
, credential_t right
)
372 dispatch_sync(auth
->dispatch_queue
, ^{
373 CFSetSetValue(auth
->authorized_rights
, right
);
378 auth_token_copy_entitlement_value(auth_token_t auth
, const char * entitlement
)
380 __block CFTypeRef value
= NULL
;
381 dispatch_sync(auth
->dispatch_queue
, ^{
383 value
= process_copy_entitlement_value(auth
->creator
, entitlement
);
391 auth_token_has_entitlement(auth_token_t auth
, const char * entitlement
)
393 __block
bool entitled
= false;
395 dispatch_sync(auth
->dispatch_queue
, ^{
397 entitled
= process_has_entitlement(auth
->creator
, entitlement
);
400 os_log_debug(AUTHD_LOG
, "authtoken: PID %d is%{public}s entitled for %{public}s", auth
->auditInfo
.pid
, entitled
? "":" not", entitlement
);
406 auth_token_has_entitlement_for_right(auth_token_t auth
, const char * right
)
408 __block
bool entitled
= false;
410 dispatch_sync(auth
->dispatch_queue
, ^{
412 entitled
= process_has_entitlement_for_right(auth
->creator
, right
);
415 os_log_debug(AUTHD_LOG
, "authtoken: PID %d is%{public}s entitled for right %{public}s", auth
->auditInfo
.pid
, entitled
? "":" not", right
);
421 auth_token_get_credential(auth_token_t auth
)
423 dispatch_sync(auth
->dispatch_queue
, ^{
424 if (auth
->credential
== NULL
) {
425 auth
->credential
= credential_create(auth
->auditInfo
.euid
);
429 return auth
->credential
;
433 auth_token_apple_signed(auth_token_t auth
)
435 return auth
->appleSigned
;
438 bool auth_token_is_creator(auth_token_t auth
, process_t proc
)
440 assert(proc
); // marked non-null
441 __block
bool creator
= false;
442 dispatch_sync(auth
->dispatch_queue
, ^{
443 if (auth
->creator
== proc
) {
450 void auth_token_set_state(auth_token_t auth
, auth_token_state_t state
)
452 auth
->state
|= state
;
455 void auth_token_clear_state(auth_token_t auth
, auth_token_state_t state
)
457 auth
->state
&= ~state
;
460 auth_token_state_t
auth_token_get_state(auth_token_t auth
)
465 bool auth_token_check_state(auth_token_t auth
, auth_token_state_t state
)
468 return (auth
->state
& state
) != 0;
470 return auth
->state
== 0;
474 CFDataRef
auth_token_get_encryption_key(auth_token_t auth
)
476 return auth
->encryption_key
;