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 static Boolean
AuthTokenEqualCallBack(const void *value1
, const void *value2
)
18 return (*(uint64_t*)value1
) == (*(uint64_t*)value2
);
21 static CFHashCode
AuthTokenHashCallBack(const void *value
)
24 // AuthorizationBlob* blob = (AuthorizationBlob*)value;
25 // hash = blob->data[1];
27 // hash |= blob->data[0];
29 //quick 64 bit aligned version
30 return *((CFHashCode
*)((AuthorizationBlob
*)value
)->data
);
33 const CFDictionaryKeyCallBacks kAuthTokenKeyCallBacks
= {
37 .copyDescription
= NULL
,
38 .equal
= &AuthTokenEqualCallBack
,
39 .hash
= &AuthTokenHashCallBack
42 struct _auth_token_s
{
43 __AUTH_BASE_STRUCT_HEADER__
;
45 AuthorizationBlob blob
;
46 auth_token_state_t state
;
47 audit_info_s auditInfo
;
48 dispatch_queue_t dispatch_queue
;
50 CFMutableSetRef processes
;
53 process_t creator
; // weak reference, used for entitlement checking
54 mach_port_t creator_bootstrap_port
;
58 CFMutableSetRef credentials
;
59 CFMutableSetRef authorized_rights
;
61 bool least_privileged
;
63 bool firstPartySigned
;
68 credential_t credential
;
72 _auth_token_finalize(CFTypeRef value
)
74 auth_token_t auth
= (auth_token_t
)value
;
75 LOGV("authtoken: deallocated %p", auth
);
77 dispatch_barrier_sync(auth
->dispatch_queue
, ^{});
79 dispatch_release(auth
->dispatch_queue
);
80 CFReleaseSafe(auth
->session
);
81 CFReleaseSafe(auth
->processes
);
82 CFReleaseSafe(auth
->context
);
83 CFReleaseSafe(auth
->credentials
);
84 CFReleaseSafe(auth
->authorized_rights
);
85 free_safe(auth
->code_url
);
86 CFReleaseSafe(auth
->credential
);
88 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
89 mach_port_deallocate(mach_task_self(), auth
->creator_bootstrap_port
);
94 _auth_token_equal(CFTypeRef value1
, CFTypeRef value2
)
96 auth_token_t auth1
= (auth_token_t
)value1
;
97 auth_token_t auth2
= (auth_token_t
)value2
;
99 return memcmp(&auth1
->blob
, &auth2
->blob
, sizeof(AuthorizationBlob
)) == 0;
103 _auth_token_copy_description(CFTypeRef value
)
105 auth_token_t auth
= (auth_token_t
)value
;
106 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("auth_token: %p, uid=%i, pid=%i, processes=%li least_privileged=%i"),
107 auth
, auth
->auditInfo
.euid
, auth
->auditInfo
.pid
, CFSetGetCount(auth
->processes
), auth
->least_privileged
);
111 _auth_token_hash(CFTypeRef value
)
113 auth_token_t auth
= (auth_token_t
)value
;
114 return *(CFHashCode
*)&auth
->blob
;
117 AUTH_TYPE_INSTANCE(auth_token
,
120 .finalize
= _auth_token_finalize
,
121 .equal
= _auth_token_equal
,
122 .hash
= _auth_token_hash
,
123 .copyFormattingDesc
= NULL
,
124 .copyDebugDesc
= _auth_token_copy_description
127 static CFTypeID
auth_token_get_type_id() {
128 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
129 static dispatch_once_t onceToken
;
131 dispatch_once(&onceToken
, ^{
132 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_token
);
139 _auth_token_create(const audit_info_s
* auditInfo
, bool operateAsLeastPrivileged
)
142 __Check_Compile_Time(sizeof(CFHashCode
) == sizeof(AuthorizationBlob
));
145 auth_token_t auth
= (auth_token_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_token_get_type_id(), AUTH_CLASS_SIZE(auth_token
), NULL
);
146 require(auth
!= NULL
, done
);
148 if (CCRandomCopyBytes(kCCRandomDefault
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != kCCSuccess
) {
149 LOGE("authtoken[%i]: failed to generate blob", auditInfo
->pid
);
154 auth
->context
= auth_items_create();
155 auth
->auditInfo
= *auditInfo
;
156 auth
->least_privileged
= operateAsLeastPrivileged
;
158 auth
->dispatch_queue
= dispatch_queue_create(NULL
, DISPATCH_QUEUE_SERIAL
);
159 check(auth
->dispatch_queue
!= NULL
);
161 auth
->credentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
162 auth
->authorized_rights
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
163 auth
->processes
= CFSetCreateMutable(kCFAllocatorDefault
, 0, NULL
);
164 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
166 if (sandbox_check(auth
->auditInfo
.pid
, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT
) != 0)
167 auth
->sandboxed
= true;
169 auth
->sandboxed
= false;
172 CFHashCode code
= AuthTokenHashCallBack(&auth
->blob
);
173 if (memcmp(&code
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != 0) {
174 LOGD("authtoken[%i]: blob = %x%01x", auth
->auditInfo
.pid
, auth
->blob
.data
[1], auth
->blob
.data
[0]);
175 LOGD("authtoken[%i]: hash = %lx", auth
->auditInfo
.pid
, code
);
185 auth_token_create(process_t proc
, bool operateAsLeastPrivileged
)
187 auth_token_t auth
= NULL
;
188 require(proc
!= NULL
, done
);
190 auth
= _auth_token_create(process_get_audit_info(proc
), operateAsLeastPrivileged
);
191 require(auth
!= NULL
, done
);
193 auth
->creator
= proc
;
194 auth
->session
= (session_t
)CFRetain(process_get_session(proc
));
195 auth
->code_url
= _copy_string(process_get_code_url(proc
));
196 auth
->appleSigned
= process_apple_signed(proc
);
197 auth
->creator_bootstrap_port
= process_get_bootstrap(proc
);
198 // This line grabs a reference to the send right to the bootstrap (our right to send to the bootstrap)
199 // This makes it critical to use the same call in reverse as we are only getting a ref to one right,
200 // but deallocate will free a ref to all 5 rights.
201 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
202 kern_return_t error_code
= mach_port_mod_refs(mach_task_self(), auth
->creator_bootstrap_port
, MACH_PORT_RIGHT_SEND
, 1);
203 if (error_code
!= KERN_SUCCESS
) {
204 // If no reference to the mach port right can be obtained, we don't hold the copy, so mark it NULL again!
205 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
209 LOGV("authtoken[%i]: created %p", auth
->auditInfo
.pid
, auth
);
216 auth_token_create_with_audit_info(const audit_info_s
* info
, bool operateAsLeastPrivileged
)
218 OSStatus status
= errSecSuccess
;
219 SecCodeRef code_Ref
= NULL
;
220 CFURLRef code_url
= NULL
;
222 auth_token_t auth
= NULL
;
223 require(info
!= NULL
, done
);
225 auth
= _auth_token_create(info
, operateAsLeastPrivileged
);
226 require(auth
!= NULL
, done
);
228 auth
->session
= server_find_copy_session(info
->asid
, true);
229 if (auth
->session
== NULL
) {
230 LOGV("authtoken[%i]: failed to create session", auth
->auditInfo
.pid
);
235 CFMutableDictionaryRef codeDict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
236 CFNumberRef codePid
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &auth
->auditInfo
.pid
);
237 CFDictionarySetValue(codeDict
, kSecGuestAttributePid
, codePid
);
238 status
= SecCodeCopyGuestWithAttributes(NULL
, codeDict
, kSecCSDefaultFlags
, &code_Ref
);
239 CFReleaseSafe(codeDict
);
240 CFReleaseSafe(codePid
);
243 LOGV("authtoken[%i]: failed to create code ref (%d)", auth
->auditInfo
.pid
, (int)status
);
248 if (SecCodeCopyPath(code_Ref
, kSecCSDefaultFlags
, &code_url
) == errSecSuccess
) {
249 auth
->code_url
= calloc(1u, PATH_MAX
+1);
250 if (auth
->code_url
) {
251 CFURLGetFileSystemRepresentation(code_url
, true, (UInt8
*)auth
->code_url
, PATH_MAX
);
255 LOGV("authtoken[%i]: created %p for %s", auth
->auditInfo
.pid
, auth
, auth
->code_url
);
258 CFReleaseSafe(code_Ref
);
259 CFReleaseSafe(code_url
);
264 auth_token_get_sandboxed(auth_token_t auth
)
266 return auth
->sandboxed
;
270 auth_token_get_code_url(auth_token_t auth
)
272 return auth
->code_url
;
276 auth_token_get_key(auth_token_t auth
)
282 auth_token_get_context(auth_token_t auth
)
284 return auth
->context
;
288 auth_token_least_privileged(auth_token_t auth
)
290 return auth
->least_privileged
;
294 auth_token_get_uid(auth_token_t auth
)
296 assert(auth
); // marked non-null
297 return auth
->auditInfo
.euid
;
301 auth_token_get_pid(auth_token_t auth
)
303 assert(auth
); // marked non-null
304 return auth
->auditInfo
.pid
;
308 auth_token_get_session(auth_token_t auth
)
310 return auth
->session
;
313 const AuthorizationBlob
*
314 auth_token_get_blob(auth_token_t auth
)
320 auth_token_get_audit_info(auth_token_t auth
)
322 return &auth
->auditInfo
;
326 auth_token_get_creator_bootstrap(auth_token_t auth
)
328 return auth
->creator_bootstrap_port
;
332 auth_token_add_process(auth_token_t auth
, process_t proc
)
334 __block CFIndex count
= 0;
335 dispatch_sync(auth
->dispatch_queue
, ^{
336 CFSetAddValue(auth
->processes
, proc
);
337 count
= CFSetGetCount(auth
->processes
);
343 auth_token_remove_process(auth_token_t auth
, process_t proc
)
345 __block CFIndex count
= 0;
346 dispatch_sync(auth
->dispatch_queue
, ^{
347 if (auth
->creator
== proc
) {
348 auth
->creator
= NULL
;
350 CFSetRemoveValue(auth
->processes
, proc
);
351 count
= CFSetGetCount(auth
->processes
);
357 auth_token_get_process_count(auth_token_t auth
)
359 __block CFIndex count
= 0;
360 dispatch_sync(auth
->dispatch_queue
, ^{
361 count
= CFSetGetCount(auth
->processes
);
367 auth_token_set_credential(auth_token_t auth
, credential_t cred
)
369 dispatch_sync(auth
->dispatch_queue
, ^{
370 CFSetSetValue(auth
->credentials
, cred
);
375 auth_token_credentials_iterate(auth_token_t auth
, credential_iterator_t iter
)
377 __block
bool result
= false;
379 dispatch_sync(auth
->dispatch_queue
, ^{
380 CFIndex count
= CFSetGetCount(auth
->credentials
);
381 CFTypeRef values
[count
];
382 CFSetGetValues(auth
->credentials
, values
);
383 for (CFIndex i
= 0; i
< count
; i
++) {
384 credential_t cred
= (credential_t
)values
[i
];
396 auth_token_set_right(auth_token_t auth
, credential_t right
)
398 dispatch_sync(auth
->dispatch_queue
, ^{
399 CFSetSetValue(auth
->authorized_rights
, right
);
404 auth_token_rights_iterate(auth_token_t auth
, credential_iterator_t iter
)
406 __block
bool result
= false;
408 dispatch_sync(auth
->dispatch_queue
, ^{
409 CFIndex count
= CFSetGetCount(auth
->authorized_rights
);
410 CFTypeRef values
[count
];
411 CFSetGetValues(auth
->authorized_rights
, values
);
412 for (CFIndex i
= 0; i
< count
; i
++) {
413 credential_t right
= (credential_t
)values
[i
];
414 result
= iter(right
);
425 auth_token_copy_entitlement_value(auth_token_t auth
, const char * entitlement
)
427 __block CFTypeRef value
= NULL
;
428 dispatch_sync(auth
->dispatch_queue
, ^{
430 value
= process_copy_entitlement_value(auth
->creator
, entitlement
);
438 auth_token_has_entitlement(auth_token_t auth
, const char * entitlement
)
440 __block
bool entitled
= false;
442 dispatch_sync(auth
->dispatch_queue
, ^{
444 entitled
= process_has_entitlement(auth
->creator
, entitlement
);
452 auth_token_has_entitlement_for_right(auth_token_t auth
, const char * right
)
454 __block
bool entitled
= false;
456 dispatch_sync(auth
->dispatch_queue
, ^{
458 entitled
= process_has_entitlement_for_right(auth
->creator
, right
);
466 auth_token_get_credential(auth_token_t auth
)
468 dispatch_sync(auth
->dispatch_queue
, ^{
469 if (auth
->credential
== NULL
) {
470 auth
->credential
= credential_create(auth
->auditInfo
.euid
);
474 return auth
->credential
;
478 auth_token_apple_signed(auth_token_t auth
)
480 return auth
->appleSigned
;
483 bool auth_token_is_creator(auth_token_t auth
, process_t proc
)
485 assert(proc
); // marked non-null
486 __block
bool creator
= false;
487 dispatch_sync(auth
->dispatch_queue
, ^{
488 if (auth
->creator
== proc
) {
495 void auth_token_set_state(auth_token_t auth
, auth_token_state_t state
)
497 auth
->state
|= state
;
500 void auth_token_clear_state(auth_token_t auth
, auth_token_state_t state
)
502 auth
->state
&= ~state
;
505 auth_token_state_t
auth_token_get_state(auth_token_t auth
)
510 bool auth_token_check_state(auth_token_t auth
, auth_token_state_t state
)
513 return (auth
->state
& state
) != 0;
515 return auth
->state
== 0;