]> git.saurik.com Git - apple/security.git/blob - OSX/authd/authtoken.c
Security-59754.41.1.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 #include <security_utilities/simulatecrash_assert.h>
17
18 AUTHD_DEFINE_LOG
19
20 static Boolean AuthTokenEqualCallBack(const void *value1, const void *value2)
21 {
22 return (*(uint64_t*)value1) == (*(uint64_t*)value2);
23 }
24
25 static CFHashCode AuthTokenHashCallBack(const void *value)
26 {
27 // CFHashCode hash;
28 // AuthorizationBlob* blob = (AuthorizationBlob*)value;
29 // hash = blob->data[1];
30 // hash <<= 32;
31 // hash |= blob->data[0];
32 // return hash;
33 //quick 64 bit aligned version
34 return *((CFHashCode*)((AuthorizationBlob*)value)->data);
35 }
36
37 const CFDictionaryKeyCallBacks kAuthTokenKeyCallBacks = {
38 .version = 0,
39 .retain = NULL,
40 .release = NULL,
41 .copyDescription = NULL,
42 .equal = &AuthTokenEqualCallBack,
43 .hash = &AuthTokenHashCallBack
44 };
45
46 struct _auth_token_s {
47 __AUTH_BASE_STRUCT_HEADER__;
48
49 AuthorizationBlob blob;
50 auth_token_state_t state;
51 audit_info_s auditInfo;
52 dispatch_queue_t dispatch_queue;
53
54 CFMutableSetRef processes;
55
56 session_t session;
57 process_t creator; // weak reference, used for entitlement checking
58 mach_port_t creator_bootstrap_port;
59
60 auth_items_t context;
61
62 CFMutableSetRef credentials;
63 CFMutableSetRef authorized_rights;
64
65 CFMutableDataRef encryption_key;
66
67 bool least_privileged;
68 bool appleSigned;
69 bool firstPartySigned;
70
71 bool sandboxed;
72 char * code_url;
73
74 credential_t credential;
75 };
76
77 static void
78 _auth_token_finalize(CFTypeRef value)
79 {
80 auth_token_t auth = (auth_token_t)value;
81 os_log_debug(AUTHD_LOG, "authtoken: finalizing");
82
83 dispatch_barrier_sync(auth->dispatch_queue, ^{});
84
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);
94
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;
98 }
99 }
100
101 static Boolean
102 _auth_token_equal(CFTypeRef value1, CFTypeRef value2)
103 {
104 auth_token_t auth1 = (auth_token_t)value1;
105 auth_token_t auth2 = (auth_token_t)value2;
106
107 return memcmp(&auth1->blob, &auth2->blob, sizeof(AuthorizationBlob)) == 0;
108 }
109
110 static CFStringRef
111 _auth_token_copy_description(CFTypeRef value)
112 {
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);
116 }
117
118 static CFHashCode
119 _auth_token_hash(CFTypeRef value)
120 {
121 auth_token_t auth = (auth_token_t)value;
122 return *(CFHashCode*)&auth->blob;
123 }
124
125 AUTH_TYPE_INSTANCE(auth_token,
126 .init = NULL,
127 .copy = NULL,
128 .finalize = _auth_token_finalize,
129 .equal = _auth_token_equal,
130 .hash = _auth_token_hash,
131 .copyFormattingDesc = NULL,
132 .copyDebugDesc = _auth_token_copy_description
133 );
134
135 static CFTypeID auth_token_get_type_id() {
136 static CFTypeID type_id = _kCFRuntimeNotATypeID;
137 static dispatch_once_t onceToken;
138
139 dispatch_once(&onceToken, ^{
140 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_token);
141 });
142
143 return type_id;
144 }
145
146 static auth_token_t
147 _auth_token_create(const audit_info_s * auditInfo, bool operateAsLeastPrivileged)
148 {
149 #if __LLP64__
150 __Check_Compile_Time(sizeof(CFHashCode) == sizeof(AuthorizationBlob));
151 #endif
152
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);
155
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);
158 CFReleaseNull(auth);
159 goto done;
160 }
161
162 auth->context = auth_items_create();
163 auth->auditInfo = *auditInfo;
164 auth->least_privileged = operateAsLeastPrivileged;
165
166 auth->dispatch_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
167 check(auth->dispatch_queue != NULL);
168
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;
173
174 if (sandbox_check_by_audit_token(auth->auditInfo.opaqueToken, "authorization-right-obtain", SANDBOX_CHECK_NO_REPORT) != 0)
175 auth->sandboxed = true;
176 else
177 auth->sandboxed = false;
178
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)
185 }
186 CFDataSetLength(auth->encryption_key, key_length);
187 }
188
189 #if DEBUG
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);
194 assert(false);
195 }
196 #endif
197
198 done:
199 return auth;
200 }
201
202 auth_token_t
203 auth_token_create(process_t proc, bool operateAsLeastPrivileged)
204 {
205 auth_token_t auth = NULL;
206 require(proc != NULL, done);
207
208 auth = _auth_token_create(process_get_audit_info(proc), operateAsLeastPrivileged);
209 require(auth != NULL, done);
210
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;
224 }
225 }
226
227 os_log_debug(AUTHD_LOG, "authtoken: created for PID %d", auth->auditInfo.pid);
228
229 done:
230 return auth;
231 }
232
233 bool
234 auth_token_get_sandboxed(auth_token_t auth)
235 {
236 return auth->sandboxed;
237 }
238
239 const char *
240 auth_token_get_code_url(auth_token_t auth)
241 {
242 return auth->code_url;
243 }
244
245 const void *
246 auth_token_get_key(auth_token_t auth)
247 {
248 return &auth->blob;
249 }
250
251 auth_items_t
252 auth_token_get_context(auth_token_t auth)
253 {
254 return auth->context;
255 }
256
257 bool
258 auth_token_least_privileged(auth_token_t auth)
259 {
260 return auth->least_privileged;
261 }
262
263 uid_t
264 auth_token_get_uid(auth_token_t auth)
265 {
266 assert(auth); // marked non-null
267 return auth->auditInfo.euid;
268 }
269
270 pid_t
271 auth_token_get_pid(auth_token_t auth)
272 {
273 assert(auth); // marked non-null
274 return auth->auditInfo.pid;
275 }
276
277 session_t
278 auth_token_get_session(auth_token_t auth)
279 {
280 return auth->session;
281 }
282
283 const AuthorizationBlob *
284 auth_token_get_blob(auth_token_t auth)
285 {
286 return &auth->blob;
287 }
288
289 const audit_info_s *
290 auth_token_get_audit_info(auth_token_t auth)
291 {
292 return &auth->auditInfo;
293 }
294
295 mach_port_t
296 auth_token_get_creator_bootstrap(auth_token_t auth)
297 {
298 return auth->creator_bootstrap_port;
299 }
300
301 CFIndex
302 auth_token_add_process(auth_token_t auth, process_t proc)
303 {
304 __block CFIndex count = 0;
305 dispatch_sync(auth->dispatch_queue, ^{
306 CFSetAddValue(auth->processes, proc);
307 count = CFSetGetCount(auth->processes);
308 });
309 return count;
310 }
311
312 CFIndex
313 auth_token_remove_process(auth_token_t auth, process_t proc)
314 {
315 __block CFIndex count = 0;
316 dispatch_sync(auth->dispatch_queue, ^{
317 if (auth->creator == proc) {
318 auth->creator = NULL;
319 }
320 CFSetRemoveValue(auth->processes, proc);
321 count = CFSetGetCount(auth->processes);
322 });
323 return count;
324 }
325
326 CFIndex
327 auth_token_get_process_count(auth_token_t auth)
328 {
329 __block CFIndex count = 0;
330 dispatch_sync(auth->dispatch_queue, ^{
331 count = CFSetGetCount(auth->processes);
332 });
333 return count;
334 }
335
336 void
337 auth_token_set_credential(auth_token_t auth, credential_t cred)
338 {
339 dispatch_sync(auth->dispatch_queue, ^{
340 CFSetSetValue(auth->credentials, cred);
341 });
342 }
343
344 bool
345 auth_token_credentials_iterate(auth_token_t auth, credential_iterator_t iter)
346 {
347 __block bool result = false;
348
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
353 count = 128;
354 }
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];
359 result = iter(cred);
360 if (!result) {
361 break;
362 }
363 }
364 });
365
366 return result;
367 }
368
369 void
370 auth_token_set_right(auth_token_t auth, credential_t right)
371 {
372 dispatch_sync(auth->dispatch_queue, ^{
373 CFSetSetValue(auth->authorized_rights, right);
374 });
375 }
376
377 CFTypeRef
378 auth_token_copy_entitlement_value(auth_token_t auth, const char * entitlement)
379 {
380 __block CFTypeRef value = NULL;
381 dispatch_sync(auth->dispatch_queue, ^{
382 if (auth->creator) {
383 value = process_copy_entitlement_value(auth->creator, entitlement);
384 }
385 });
386
387 return value;
388 }
389
390 bool
391 auth_token_has_entitlement(auth_token_t auth, const char * entitlement)
392 {
393 __block bool entitled = false;
394
395 dispatch_sync(auth->dispatch_queue, ^{
396 if (auth->creator) {
397 entitled = process_has_entitlement(auth->creator, entitlement);
398 }
399 });
400 os_log_debug(AUTHD_LOG, "authtoken: PID %d is%{public}s entitled for %{public}s", auth->auditInfo.pid, entitled ? "":" not", entitlement);
401
402 return entitled;
403 }
404
405 bool
406 auth_token_has_entitlement_for_right(auth_token_t auth, const char * right)
407 {
408 __block bool entitled = false;
409
410 dispatch_sync(auth->dispatch_queue, ^{
411 if (auth->creator) {
412 entitled = process_has_entitlement_for_right(auth->creator, right);
413 }
414 });
415 os_log_debug(AUTHD_LOG, "authtoken: PID %d is%{public}s entitled for right %{public}s", auth->auditInfo.pid, entitled ? "":" not", right);
416
417 return entitled;
418 }
419
420 credential_t
421 auth_token_get_credential(auth_token_t auth)
422 {
423 dispatch_sync(auth->dispatch_queue, ^{
424 if (auth->credential == NULL) {
425 auth->credential = credential_create(auth->auditInfo.euid);
426 }
427 });
428
429 return auth->credential;
430 }
431
432 bool
433 auth_token_apple_signed(auth_token_t auth)
434 {
435 return auth->appleSigned;
436 }
437
438 bool auth_token_is_creator(auth_token_t auth, process_t proc)
439 {
440 assert(proc); // marked non-null
441 __block bool creator = false;
442 dispatch_sync(auth->dispatch_queue, ^{
443 if (auth->creator == proc) {
444 creator = true;
445 }
446 });
447 return creator;
448 }
449
450 void auth_token_set_state(auth_token_t auth, auth_token_state_t state)
451 {
452 auth->state |= state;
453 }
454
455 void auth_token_clear_state(auth_token_t auth, auth_token_state_t state)
456 {
457 auth->state &= ~state;
458 }
459
460 auth_token_state_t auth_token_get_state(auth_token_t auth)
461 {
462 return auth->state;
463 }
464
465 bool auth_token_check_state(auth_token_t auth, auth_token_state_t state)
466 {
467 if (state) {
468 return (auth->state & state) != 0;
469 } else {
470 return auth->state == 0;
471 }
472 }
473
474 CFDataRef auth_token_get_encryption_key(auth_token_t auth)
475 {
476 return auth->encryption_key;
477 }
478