]> git.saurik.com Git - apple/security.git/blob - OSX/authd/authtoken.c
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / authd / authtoken.c
1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
2
3 #include "authtoken.h"
4 #include "authd_private.h"
5 #include "process.h"
6 #include "authitems.h"
7 #include "debugging.h"
8 #include "authutilities.h"
9 #include "server.h"
10
11 #include <CommonCrypto/CommonRandomSPI.h>
12 #include <Security/Authorization.h>
13 #include <Security/SecBase.h>
14 #include <sandbox.h>
15
16 AUTHD_DEFINE_LOG
17
18 static Boolean AuthTokenEqualCallBack(const void *value1, const void *value2)
19 {
20 return (*(uint64_t*)value1) == (*(uint64_t*)value2);
21 }
22
23 static CFHashCode AuthTokenHashCallBack(const void *value)
24 {
25 // CFHashCode hash;
26 // AuthorizationBlob* blob = (AuthorizationBlob*)value;
27 // hash = blob->data[1];
28 // hash <<= 32;
29 // hash |= blob->data[0];
30 // return hash;
31 //quick 64 bit aligned version
32 return *((CFHashCode*)((AuthorizationBlob*)value)->data);
33 }
34
35 const CFDictionaryKeyCallBacks kAuthTokenKeyCallBacks = {
36 .version = 0,
37 .retain = NULL,
38 .release = NULL,
39 .copyDescription = NULL,
40 .equal = &AuthTokenEqualCallBack,
41 .hash = &AuthTokenHashCallBack
42 };
43
44 struct _auth_token_s {
45 __AUTH_BASE_STRUCT_HEADER__;
46
47 AuthorizationBlob blob;
48 auth_token_state_t state;
49 audit_info_s auditInfo;
50 dispatch_queue_t dispatch_queue;
51
52 CFMutableSetRef processes;
53
54 session_t session;
55 process_t creator; // weak reference, used for entitlement checking
56 mach_port_t creator_bootstrap_port;
57
58 auth_items_t context;
59
60 CFMutableSetRef credentials;
61 CFMutableSetRef authorized_rights;
62
63 CFMutableDataRef encryption_key;
64
65 bool least_privileged;
66 bool appleSigned;
67 bool firstPartySigned;
68
69 bool sandboxed;
70 char * code_url;
71
72 credential_t credential;
73 };
74
75 static void
76 _auth_token_finalize(CFTypeRef value)
77 {
78 auth_token_t auth = (auth_token_t)value;
79 os_log_debug(AUTHD_LOG, "authtoken: finalizing");
80
81 dispatch_barrier_sync(auth->dispatch_queue, ^{});
82
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);
92
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;
96 }
97 }
98
99 static Boolean
100 _auth_token_equal(CFTypeRef value1, CFTypeRef value2)
101 {
102 auth_token_t auth1 = (auth_token_t)value1;
103 auth_token_t auth2 = (auth_token_t)value2;
104
105 return memcmp(&auth1->blob, &auth2->blob, sizeof(AuthorizationBlob)) == 0;
106 }
107
108 static CFStringRef
109 _auth_token_copy_description(CFTypeRef value)
110 {
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);
114 }
115
116 static CFHashCode
117 _auth_token_hash(CFTypeRef value)
118 {
119 auth_token_t auth = (auth_token_t)value;
120 return *(CFHashCode*)&auth->blob;
121 }
122
123 AUTH_TYPE_INSTANCE(auth_token,
124 .init = NULL,
125 .copy = NULL,
126 .finalize = _auth_token_finalize,
127 .equal = _auth_token_equal,
128 .hash = _auth_token_hash,
129 .copyFormattingDesc = NULL,
130 .copyDebugDesc = _auth_token_copy_description
131 );
132
133 static CFTypeID auth_token_get_type_id() {
134 static CFTypeID type_id = _kCFRuntimeNotATypeID;
135 static dispatch_once_t onceToken;
136
137 dispatch_once(&onceToken, ^{
138 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_token);
139 });
140
141 return type_id;
142 }
143
144 static auth_token_t
145 _auth_token_create(const audit_info_s * auditInfo, bool operateAsLeastPrivileged)
146 {
147 #if __LLP64__
148 __Check_Compile_Time(sizeof(CFHashCode) == sizeof(AuthorizationBlob));
149 #endif
150
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);
153
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);
156 CFReleaseNull(auth);
157 goto done;
158 }
159
160 auth->context = auth_items_create();
161 auth->auditInfo = *auditInfo;
162 auth->least_privileged = operateAsLeastPrivileged;
163
164 auth->dispatch_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
165 check(auth->dispatch_queue != NULL);
166
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;
171
172 if (sandbox_check(auth->auditInfo.pid, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT) != 0)
173 auth->sandboxed = true;
174 else
175 auth->sandboxed = false;
176
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)
183 }
184 CFDataSetLength(auth->encryption_key, key_length);
185 }
186
187 #if DEBUG
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);
192 assert(false);
193 }
194 #endif
195
196 done:
197 return auth;
198 }
199
200 auth_token_t
201 auth_token_create(process_t proc, bool operateAsLeastPrivileged)
202 {
203 auth_token_t auth = NULL;
204 require(proc != NULL, done);
205
206 auth = _auth_token_create(process_get_audit_info(proc), operateAsLeastPrivileged);
207 require(auth != NULL, done);
208
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;
222 }
223 }
224
225 os_log_debug(AUTHD_LOG, "authtoken: created for PID %d", auth->auditInfo.pid);
226
227 done:
228 return auth;
229 }
230
231 auth_token_t
232 auth_token_create_with_audit_info(const audit_info_s* info, bool operateAsLeastPrivileged)
233 {
234 OSStatus status = errSecSuccess;
235 SecCodeRef code_Ref = NULL;
236 CFURLRef code_url = NULL;
237
238 auth_token_t auth = NULL;
239 require(info != NULL, done);
240
241 auth = _auth_token_create(info, operateAsLeastPrivileged);
242 require(auth != NULL, done);
243
244 auth->session = server_find_copy_session(info->asid, true);
245 if (auth->session == NULL) {
246 os_log_debug(AUTHD_LOG, "authtoken: failed to create session (PID %d)", auth->auditInfo.pid);
247 CFReleaseNull(auth);
248 goto done;
249 }
250
251 CFMutableDictionaryRef codeDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
252 CFNumberRef codePid = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &auth->auditInfo.pid);
253 CFDictionarySetValue(codeDict, kSecGuestAttributePid, codePid);
254 status = SecCodeCopyGuestWithAttributes(NULL, codeDict, kSecCSDefaultFlags, &code_Ref);
255 CFReleaseSafe(codeDict);
256 CFReleaseSafe(codePid);
257
258 if (status) {
259 os_log_debug(AUTHD_LOG, "authtoken: failed to create code ref (%d)", (int)status);
260 CFReleaseNull(auth);
261 goto done;
262 }
263
264 if (SecCodeCopyPath(code_Ref, kSecCSDefaultFlags, &code_url) == errSecSuccess) {
265 auth->code_url = calloc(1u, PATH_MAX+1);
266 if (auth->code_url) {
267 CFURLGetFileSystemRepresentation(code_url, true, (UInt8*)auth->code_url, PATH_MAX);
268 }
269 }
270
271 os_log_debug(AUTHD_LOG, "authtoken: created for %{public}s", auth->code_url);
272
273 done:
274 CFReleaseSafe(code_Ref);
275 CFReleaseSafe(code_url);
276 return auth;
277 }
278
279 bool
280 auth_token_get_sandboxed(auth_token_t auth)
281 {
282 return auth->sandboxed;
283 }
284
285 const char *
286 auth_token_get_code_url(auth_token_t auth)
287 {
288 return auth->code_url;
289 }
290
291 const void *
292 auth_token_get_key(auth_token_t auth)
293 {
294 return &auth->blob;
295 }
296
297 auth_items_t
298 auth_token_get_context(auth_token_t auth)
299 {
300 return auth->context;
301 }
302
303 bool
304 auth_token_least_privileged(auth_token_t auth)
305 {
306 return auth->least_privileged;
307 }
308
309 uid_t
310 auth_token_get_uid(auth_token_t auth)
311 {
312 assert(auth); // marked non-null
313 return auth->auditInfo.euid;
314 }
315
316 pid_t
317 auth_token_get_pid(auth_token_t auth)
318 {
319 assert(auth); // marked non-null
320 return auth->auditInfo.pid;
321 }
322
323 session_t
324 auth_token_get_session(auth_token_t auth)
325 {
326 return auth->session;
327 }
328
329 const AuthorizationBlob *
330 auth_token_get_blob(auth_token_t auth)
331 {
332 return &auth->blob;
333 }
334
335 const audit_info_s *
336 auth_token_get_audit_info(auth_token_t auth)
337 {
338 return &auth->auditInfo;
339 }
340
341 mach_port_t
342 auth_token_get_creator_bootstrap(auth_token_t auth)
343 {
344 return auth->creator_bootstrap_port;
345 }
346
347 CFIndex
348 auth_token_add_process(auth_token_t auth, process_t proc)
349 {
350 __block CFIndex count = 0;
351 dispatch_sync(auth->dispatch_queue, ^{
352 CFSetAddValue(auth->processes, proc);
353 count = CFSetGetCount(auth->processes);
354 });
355 return count;
356 }
357
358 CFIndex
359 auth_token_remove_process(auth_token_t auth, process_t proc)
360 {
361 __block CFIndex count = 0;
362 dispatch_sync(auth->dispatch_queue, ^{
363 if (auth->creator == proc) {
364 auth->creator = NULL;
365 }
366 CFSetRemoveValue(auth->processes, proc);
367 count = CFSetGetCount(auth->processes);
368 });
369 return count;
370 }
371
372 CFIndex
373 auth_token_get_process_count(auth_token_t auth)
374 {
375 __block CFIndex count = 0;
376 dispatch_sync(auth->dispatch_queue, ^{
377 count = CFSetGetCount(auth->processes);
378 });
379 return count;
380 }
381
382 void
383 auth_token_set_credential(auth_token_t auth, credential_t cred)
384 {
385 dispatch_sync(auth->dispatch_queue, ^{
386 CFSetSetValue(auth->credentials, cred);
387 });
388 }
389
390 bool
391 auth_token_credentials_iterate(auth_token_t auth, credential_iterator_t iter)
392 {
393 __block bool result = false;
394
395 dispatch_sync(auth->dispatch_queue, ^{
396 CFIndex count = CFSetGetCount(auth->credentials);
397 CFTypeRef values[count];
398 CFSetGetValues(auth->credentials, values);
399 for (CFIndex i = 0; i < count; i++) {
400 credential_t cred = (credential_t)values[i];
401 result = iter(cred);
402 if (!result) {
403 break;
404 }
405 }
406 });
407
408 return result;
409 }
410
411 void
412 auth_token_set_right(auth_token_t auth, credential_t right)
413 {
414 dispatch_sync(auth->dispatch_queue, ^{
415 CFSetSetValue(auth->authorized_rights, right);
416 });
417 }
418
419 bool
420 auth_token_rights_iterate(auth_token_t auth, credential_iterator_t iter)
421 {
422 __block bool result = false;
423
424 dispatch_sync(auth->dispatch_queue, ^{
425 CFIndex count = CFSetGetCount(auth->authorized_rights);
426 CFTypeRef values[count];
427 CFSetGetValues(auth->authorized_rights, values);
428 for (CFIndex i = 0; i < count; i++) {
429 credential_t right = (credential_t)values[i];
430 result = iter(right);
431 if (!result) {
432 break;
433 }
434 }
435 });
436
437 return result;
438 }
439
440 CFTypeRef
441 auth_token_copy_entitlement_value(auth_token_t auth, const char * entitlement)
442 {
443 __block CFTypeRef value = NULL;
444 dispatch_sync(auth->dispatch_queue, ^{
445 if (auth->creator) {
446 value = process_copy_entitlement_value(auth->creator, entitlement);
447 }
448 });
449
450 return value;
451 }
452
453 bool
454 auth_token_has_entitlement(auth_token_t auth, const char * entitlement)
455 {
456 __block bool entitled = false;
457
458 dispatch_sync(auth->dispatch_queue, ^{
459 if (auth->creator) {
460 entitled = process_has_entitlement(auth->creator, entitlement);
461 }
462 });
463
464 return entitled;
465 }
466
467 bool
468 auth_token_has_entitlement_for_right(auth_token_t auth, const char * right)
469 {
470 __block bool entitled = false;
471
472 dispatch_sync(auth->dispatch_queue, ^{
473 if (auth->creator) {
474 entitled = process_has_entitlement_for_right(auth->creator, right);
475 }
476 });
477
478 return entitled;
479 }
480
481 credential_t
482 auth_token_get_credential(auth_token_t auth)
483 {
484 dispatch_sync(auth->dispatch_queue, ^{
485 if (auth->credential == NULL) {
486 auth->credential = credential_create(auth->auditInfo.euid);
487 }
488 });
489
490 return auth->credential;
491 }
492
493 bool
494 auth_token_apple_signed(auth_token_t auth)
495 {
496 return auth->appleSigned;
497 }
498
499 bool auth_token_is_creator(auth_token_t auth, process_t proc)
500 {
501 assert(proc); // marked non-null
502 __block bool creator = false;
503 dispatch_sync(auth->dispatch_queue, ^{
504 if (auth->creator == proc) {
505 creator = true;
506 }
507 });
508 return creator;
509 }
510
511 void auth_token_set_state(auth_token_t auth, auth_token_state_t state)
512 {
513 auth->state |= state;
514 }
515
516 void auth_token_clear_state(auth_token_t auth, auth_token_state_t state)
517 {
518 auth->state &= ~state;
519 }
520
521 auth_token_state_t auth_token_get_state(auth_token_t auth)
522 {
523 return auth->state;
524 }
525
526 bool auth_token_check_state(auth_token_t auth, auth_token_state_t state)
527 {
528 if (state) {
529 return (auth->state & state) != 0;
530 } else {
531 return auth->state == 0;
532 }
533 }
534
535 CFDataRef auth_token_get_encryption_key(auth_token_t auth)
536 {
537 return auth->encryption_key;
538 }
539