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
;
67 credential_t credential
;
71 _auth_token_finalize(CFTypeRef value
)
73 auth_token_t auth
= (auth_token_t
)value
;
74 LOGV("authtoken: deallocated %p", auth
);
76 dispatch_barrier_sync(auth
->dispatch_queue
, ^{});
78 dispatch_release(auth
->dispatch_queue
);
79 CFReleaseSafe(auth
->session
);
80 CFReleaseSafe(auth
->processes
);
81 CFReleaseSafe(auth
->context
);
82 CFReleaseSafe(auth
->credentials
);
83 CFReleaseSafe(auth
->authorized_rights
);
84 free_safe(auth
->code_url
);
85 CFReleaseSafe(auth
->credential
);
87 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
88 mach_port_deallocate(mach_task_self(), auth
->creator_bootstrap_port
);
93 _auth_token_equal(CFTypeRef value1
, CFTypeRef value2
)
95 auth_token_t auth1
= (auth_token_t
)value1
;
96 auth_token_t auth2
= (auth_token_t
)value2
;
98 return memcmp(&auth1
->blob
, &auth2
->blob
, sizeof(AuthorizationBlob
)) == 0;
102 _auth_token_copy_description(CFTypeRef value
)
104 auth_token_t auth
= (auth_token_t
)value
;
105 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("auth_token: %p, uid=%i, pid=%i, processes=%li least_privileged=%i"),
106 auth
, auth
->auditInfo
.euid
, auth
->auditInfo
.pid
, CFSetGetCount(auth
->processes
), auth
->least_privileged
);
110 _auth_token_hash(CFTypeRef value
)
112 auth_token_t auth
= (auth_token_t
)value
;
113 return *(CFHashCode
*)&auth
->blob
;
116 AUTH_TYPE_INSTANCE(auth_token
,
119 .finalize
= _auth_token_finalize
,
120 .equal
= _auth_token_equal
,
121 .hash
= _auth_token_hash
,
122 .copyFormattingDesc
= NULL
,
123 .copyDebugDesc
= _auth_token_copy_description
126 static CFTypeID
auth_token_get_type_id() {
127 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
128 static dispatch_once_t onceToken
;
130 dispatch_once(&onceToken
, ^{
131 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_token
);
138 _auth_token_create(const audit_info_s
* auditInfo
, bool operateAsLeastPrivileged
)
141 __Check_Compile_Time(sizeof(CFHashCode
) == sizeof(AuthorizationBlob
));
144 auth_token_t auth
= (auth_token_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_token_get_type_id(), AUTH_CLASS_SIZE(auth_token
), NULL
);
145 require(auth
!= NULL
, done
);
147 if (CCRandomCopyBytes(kCCRandomDefault
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != kCCSuccess
) {
148 LOGE("authtoken[%i]: failed to generate blob", auditInfo
->pid
);
153 auth
->context
= auth_items_create();
154 auth
->auditInfo
= *auditInfo
;
155 auth
->least_privileged
= operateAsLeastPrivileged
;
157 auth
->dispatch_queue
= dispatch_queue_create(NULL
, DISPATCH_QUEUE_SERIAL
);
158 check(auth
->dispatch_queue
!= NULL
);
160 auth
->credentials
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
161 auth
->authorized_rights
= CFSetCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeSetCallBacks
);
162 auth
->processes
= CFSetCreateMutable(kCFAllocatorDefault
, 0, NULL
);
163 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
165 if (sandbox_check(auth
->auditInfo
.pid
, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT
) != 0)
166 auth
->sandboxed
= true;
168 auth
->sandboxed
= false;
171 CFHashCode code
= AuthTokenHashCallBack(&auth
->blob
);
172 if (memcmp(&code
, auth
->blob
.data
, sizeof(auth
->blob
.data
)) != 0) {
173 LOGD("authtoken[%i]: blob = %x%01x", auth
->auditInfo
.pid
, auth
->blob
.data
[1], auth
->blob
.data
[0]);
174 LOGD("authtoken[%i]: hash = %lx", auth
->auditInfo
.pid
, code
);
184 auth_token_create(process_t proc
, bool operateAsLeastPrivileged
)
186 auth_token_t auth
= NULL
;
187 require(proc
!= NULL
, done
);
189 auth
= _auth_token_create(process_get_audit_info(proc
), operateAsLeastPrivileged
);
190 require(auth
!= NULL
, done
);
192 auth
->creator
= proc
;
193 auth
->session
= (session_t
)CFRetain(process_get_session(proc
));
194 auth
->code_url
= _copy_string(process_get_code_url(proc
));
195 auth
->appleSigned
= process_apple_signed(proc
);
196 auth
->creator_bootstrap_port
= process_get_bootstrap(proc
);
197 // This line grabs a reference to the send right to the bootstrap (our right to send to the bootstrap)
198 // This makes it critical to use the same call in reverse as we are only getting a ref to one right,
199 // but deallocate will free a ref to all 5 rights.
200 if (auth
->creator_bootstrap_port
!= MACH_PORT_NULL
) {
201 kern_return_t error_code
= mach_port_mod_refs(mach_task_self(), auth
->creator_bootstrap_port
, MACH_PORT_RIGHT_SEND
, 1);
202 if (error_code
!= KERN_SUCCESS
) {
203 // If no reference to the mach port right can be obtained, we don't hold the copy, so mark it NULL again!
204 auth
->creator_bootstrap_port
= MACH_PORT_NULL
;
208 LOGV("authtoken[%i]: created %p", auth
->auditInfo
.pid
, auth
);
215 auth_token_create_with_audit_info(const audit_info_s
* info
, bool operateAsLeastPrivileged
)
217 OSStatus status
= errSecSuccess
;
218 SecCodeRef code_Ref
= NULL
;
219 CFURLRef code_url
= NULL
;
221 auth_token_t auth
= NULL
;
222 require(info
!= NULL
, done
);
224 auth
= _auth_token_create(info
, operateAsLeastPrivileged
);
225 require(auth
!= NULL
, done
);
227 auth
->session
= server_find_copy_session(info
->asid
, true);
228 if (auth
->session
== NULL
) {
229 LOGV("authtoken[%i]: failed to create session", auth
->auditInfo
.pid
);
234 CFMutableDictionaryRef codeDict
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
235 CFNumberRef codePid
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &auth
->auditInfo
.pid
);
236 CFDictionarySetValue(codeDict
, kSecGuestAttributePid
, codePid
);
237 status
= SecCodeCopyGuestWithAttributes(NULL
, codeDict
, kSecCSDefaultFlags
, &code_Ref
);
238 CFReleaseSafe(codeDict
);
239 CFReleaseSafe(codePid
);
242 LOGV("authtoken[%i]: failed to create code ref (%d)", auth
->auditInfo
.pid
, (int)status
);
247 if (SecCodeCopyPath(code_Ref
, kSecCSDefaultFlags
, &code_url
) == errSecSuccess
) {
248 auth
->code_url
= calloc(1u, PATH_MAX
+1);
249 if (auth
->code_url
) {
250 CFURLGetFileSystemRepresentation(code_url
, true, (UInt8
*)auth
->code_url
, PATH_MAX
);
254 LOGV("authtoken[%i]: created %p for %s", auth
->auditInfo
.pid
, auth
, auth
->code_url
);
257 CFReleaseSafe(code_Ref
);
258 CFReleaseSafe(code_url
);
263 auth_token_get_sandboxed(auth_token_t auth
)
265 return auth
->sandboxed
;
269 auth_token_get_code_url(auth_token_t auth
)
271 return auth
->code_url
;
275 auth_token_get_key(auth_token_t auth
)
281 auth_token_get_context(auth_token_t auth
)
283 return auth
->context
;
287 auth_token_least_privileged(auth_token_t auth
)
289 return auth
->least_privileged
;
293 auth_token_get_uid(auth_token_t auth
)
295 assert(auth
); // marked non-null
296 return auth
->auditInfo
.euid
;
300 auth_token_get_pid(auth_token_t auth
)
302 assert(auth
); // marked non-null
303 return auth
->auditInfo
.pid
;
307 auth_token_get_session(auth_token_t auth
)
309 return auth
->session
;
312 const AuthorizationBlob
*
313 auth_token_get_blob(auth_token_t auth
)
319 auth_token_get_audit_info(auth_token_t auth
)
321 return &auth
->auditInfo
;
325 auth_token_get_creator_bootstrap(auth_token_t auth
)
327 return auth
->creator_bootstrap_port
;
331 auth_token_add_process(auth_token_t auth
, process_t proc
)
333 __block CFIndex count
= 0;
334 dispatch_sync(auth
->dispatch_queue
, ^{
335 CFSetAddValue(auth
->processes
, proc
);
336 count
= CFSetGetCount(auth
->processes
);
342 auth_token_remove_process(auth_token_t auth
, process_t proc
)
344 __block CFIndex count
= 0;
345 dispatch_sync(auth
->dispatch_queue
, ^{
346 if (auth
->creator
== proc
) {
347 auth
->creator
= NULL
;
349 CFSetRemoveValue(auth
->processes
, proc
);
350 count
= CFSetGetCount(auth
->processes
);
356 auth_token_get_process_count(auth_token_t auth
)
358 __block CFIndex count
= 0;
359 dispatch_sync(auth
->dispatch_queue
, ^{
360 count
= CFSetGetCount(auth
->processes
);
366 auth_token_set_credential(auth_token_t auth
, credential_t cred
)
368 dispatch_sync(auth
->dispatch_queue
, ^{
369 CFSetSetValue(auth
->credentials
, cred
);
374 auth_token_credentials_iterate(auth_token_t auth
, credential_iterator_t iter
)
376 __block
bool result
= false;
378 dispatch_sync(auth
->dispatch_queue
, ^{
379 CFIndex count
= CFSetGetCount(auth
->credentials
);
380 CFTypeRef values
[count
];
381 CFSetGetValues(auth
->credentials
, values
);
382 for (CFIndex i
= 0; i
< count
; i
++) {
383 credential_t cred
= (credential_t
)values
[i
];
395 auth_token_set_right(auth_token_t auth
, credential_t right
)
397 dispatch_sync(auth
->dispatch_queue
, ^{
398 CFSetSetValue(auth
->authorized_rights
, right
);
403 auth_token_rights_iterate(auth_token_t auth
, credential_iterator_t iter
)
405 __block
bool result
= false;
407 dispatch_sync(auth
->dispatch_queue
, ^{
408 CFIndex count
= CFSetGetCount(auth
->authorized_rights
);
409 CFTypeRef values
[count
];
410 CFSetGetValues(auth
->authorized_rights
, values
);
411 for (CFIndex i
= 0; i
< count
; i
++) {
412 credential_t right
= (credential_t
)values
[i
];
413 result
= iter(right
);
424 auth_token_copy_entitlement_value(auth_token_t auth
, const char * entitlement
)
426 __block CFTypeRef value
= NULL
;
427 dispatch_sync(auth
->dispatch_queue
, ^{
429 value
= process_copy_entitlement_value(auth
->creator
, entitlement
);
437 auth_token_has_entitlement(auth_token_t auth
, const char * entitlement
)
439 __block
bool entitled
= false;
441 dispatch_sync(auth
->dispatch_queue
, ^{
443 entitled
= process_has_entitlement(auth
->creator
, entitlement
);
451 auth_token_has_entitlement_for_right(auth_token_t auth
, const char * right
)
453 __block
bool entitled
= false;
455 dispatch_sync(auth
->dispatch_queue
, ^{
457 entitled
= process_has_entitlement_for_right(auth
->creator
, right
);
465 auth_token_get_credential(auth_token_t auth
)
467 dispatch_sync(auth
->dispatch_queue
, ^{
468 if (auth
->credential
== NULL
) {
469 auth
->credential
= credential_create(auth
->auditInfo
.euid
);
473 return auth
->credential
;
477 auth_token_apple_signed(auth_token_t auth
)
479 return auth
->appleSigned
;
482 bool auth_token_is_creator(auth_token_t auth
, process_t proc
)
484 assert(proc
); // marked non-null
485 __block
bool creator
= false;
486 dispatch_sync(auth
->dispatch_queue
, ^{
487 if (auth
->creator
== proc
) {
494 void auth_token_set_state(auth_token_t auth
, auth_token_state_t state
)
496 auth
->state
|= state
;
499 void auth_token_clear_state(auth_token_t auth
, auth_token_state_t state
)
501 auth
->state
&= ~state
;
504 auth_token_state_t
auth_token_get_state(auth_token_t auth
)
509 bool auth_token_check_state(auth_token_t auth
, auth_token_state_t state
)
512 return (auth
->state
& state
) != 0;
514 return auth
->state
== 0;