]> git.saurik.com Git - apple/security.git/blob - OSX/authd/authitems.c
abac3452769fe3912cef3d55deda01bfb20f17f7
[apple/security.git] / OSX / authd / authitems.c
1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
2
3 #include "authitems.h"
4 #include "crc.h"
5 #include "debugging.h"
6
7 #include "authutilities.h"
8 #include <Security/AuthorizationTags.h>
9 #include <dispatch/private.h>
10
11 typedef struct _auth_item_s * auth_item_t;
12
13 #pragma mark -
14 #pragma mark auth_item_t
15
16 struct _auth_item_s {
17 __AUTH_BASE_STRUCT_HEADER__;
18
19 AuthorizationItem data;
20 uint32_t type;
21 size_t bufLen;
22
23 CFStringRef cfKey;
24 };
25
26 static const char *
27 auth_item_get_string(auth_item_t item)
28 {
29 if (item->bufLen <= item->data.valueLength) {
30 item->bufLen = item->data.valueLength+1; // make sure buffer has a null char
31 item->data.value = realloc(item->data.value, item->bufLen);
32 if (item->data.value == NULL) {
33 // this is added to prevent running off into random memory if a string buffer doesn't have a null char
34 LOGE("realloc failed");
35 abort();
36 }
37 ((uint8_t*)item->data.value)[item->bufLen-1] = '\0';
38 }
39 return item->data.value;
40 }
41
42 static CFStringRef
43 auth_item_get_cf_key(auth_item_t item)
44 {
45 if (!item->cfKey) {
46 item->cfKey = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, item->data.name, kCFStringEncodingUTF8, kCFAllocatorNull);
47 }
48 return item->cfKey;
49 }
50
51 static AuthorizationItem *
52 auth_item_get_auth_item(auth_item_t item)
53 {
54 return &item->data;
55 }
56
57 static xpc_object_t
58 auth_item_copy_auth_item_xpc(auth_item_t item)
59 {
60 xpc_object_t xpc_data = xpc_dictionary_create(NULL, NULL, 0);
61 xpc_dictionary_set_string(xpc_data, AUTH_XPC_ITEM_NAME, item->data.name);
62 if (item->data.value) {
63 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
64 bool sensitive = strcmp(item->data.name, "password") == 0;
65 if (sensitive) {
66 vm_address_t vmBytes = 0;
67 size_t xpcOutOfBandBlockSize = (item->data.valueLength > 32768 ? item->data.valueLength : 32768); // min 16K on 64-bit systems and 12K on 32-bit systems
68 vm_allocate(mach_task_self(), &vmBytes, xpcOutOfBandBlockSize, VM_FLAGS_ANYWHERE);
69 memcpy((void *)vmBytes, item->data.value, item->data.valueLength);
70 dispatch_data_t dispData = dispatch_data_create((void *)vmBytes, xpcOutOfBandBlockSize, DISPATCH_TARGET_QUEUE_DEFAULT, DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE); // out-of-band mapping
71 xpc_object_t xpcData = xpc_data_create_with_dispatch_data(dispData);
72 dispatch_release(dispData);
73 xpc_dictionary_set_value(xpc_data, AUTH_XPC_ITEM_VALUE, xpcData);
74 xpc_release(xpcData);
75 xpc_dictionary_set_uint64(xpc_data, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH, item->data.valueLength);
76 } else {
77 xpc_dictionary_set_data(xpc_data, AUTH_XPC_ITEM_VALUE, item->data.value, item->data.valueLength);
78 }
79 }
80 xpc_dictionary_set_uint64(xpc_data, AUTH_XPC_ITEM_FLAGS, item->data.flags);
81 xpc_dictionary_set_uint64(xpc_data, AUTH_XPC_ITEM_TYPE, item->type);
82 return xpc_data;
83 }
84
85 static void
86 _auth_item_finalize(CFTypeRef value)
87 {
88 auth_item_t item = (auth_item_t)value;
89
90 CFReleaseSafe(item->cfKey);
91
92 if (item->data.name) {
93 free((void*)item->data.name);
94 }
95
96 if (item->data.value) {
97 memset(item->data.value, 0, item->data.valueLength);
98 free(item->data.value);
99 }
100 }
101
102 static Boolean
103 _auth_item_equal(CFTypeRef value1, CFTypeRef value2)
104 {
105 return (CFHash(value1) == CFHash(value2));
106 }
107
108 static CFStringRef
109 _auth_item_copy_description(CFTypeRef value)
110 {
111 bool hidden = false;
112 auth_item_t item = (auth_item_t)value;
113
114 #ifndef DEBUG
115 static size_t passLen = strlen(kAuthorizationEnvironmentPassword);
116 if (strncasecmp(item->data.name, kAuthorizationEnvironmentPassword, passLen) == 0) {
117 hidden = true;
118 }
119 #endif
120
121 CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0);
122 CFStringAppendFormat(desc, NULL, CFSTR("auth_item: %s, type=%i, length=%li, flags=%x"),
123 item->data.name, item->type,
124 hidden ? 0 : item->data.valueLength, (unsigned int)item->data.flags);
125
126 switch (item->type) {
127 case AI_TYPE_STRING:
128 CFStringAppendFormat(desc, NULL, CFSTR(" value=%s"), hidden ? "(hidden)" : auth_item_get_string(item));
129 break;
130 case AI_TYPE_INT:
131 CFStringAppendFormat(desc, NULL, CFSTR(" value=%i"), *(int32_t*)item->data.value);
132 break;
133 case AI_TYPE_UINT:
134 CFStringAppendFormat(desc, NULL, CFSTR(" value=%u"), *(uint32_t*)item->data.value);
135 break;
136 case AI_TYPE_INT64:
137 CFStringAppendFormat(desc, NULL, CFSTR(" value=%lli"), *(int64_t*)item->data.value);
138 break;
139 case AI_TYPE_UINT64:
140 CFStringAppendFormat(desc, NULL, CFSTR(" value=%llu"), *(uint64_t*)item->data.value);
141 break;
142 case AI_TYPE_BOOL:
143 CFStringAppendFormat(desc, NULL, CFSTR(" value=%i"), *(bool*)item->data.value);
144 break;
145 case AI_TYPE_DOUBLE:
146 CFStringAppendFormat(desc, NULL, CFSTR(" value=%f"), *(double*)item->data.value);
147 break;
148 case AI_TYPE_DATA:
149 case AI_TYPE_UNKNOWN:
150 if (hidden) {
151 CFStringAppendFormat(desc, NULL, CFSTR(" value=(hidden)"));
152 } else {
153 CFStringAppendFormat(desc, NULL, CFSTR(" value=0x"));
154 size_t i = item->data.valueLength < 10 ? item->data.valueLength : 10;
155 uint8_t * data = item->data.value;
156 for (; i > 0; i--) {
157 CFStringAppendFormat(desc, NULL, CFSTR("%02x"), data[i-1]);
158 }
159 }
160 break;
161 default:
162 break;
163 }
164 return desc;
165 }
166
167 static CFHashCode
168 _auth_item_hash(CFTypeRef value)
169 {
170 auth_item_t item = (auth_item_t)value;
171 uint64_t crc = crc64_init();
172 crc = crc64_update(crc, item->data.name, strlen(item->data.name));
173 if (item->data.value) {
174 crc = crc64_update(crc, item->data.value, item->data.valueLength);
175 }
176 crc = crc64_update(crc, &item->data.flags, sizeof(item->data.flags));
177
178 crc = crc64_final(crc);
179 return (CFHashCode)crc;
180 }
181
182 AUTH_TYPE_INSTANCE(auth_item,
183 .init = NULL,
184 .copy = NULL,
185 .finalize = _auth_item_finalize,
186 .equal = _auth_item_equal,
187 .hash = _auth_item_hash,
188 .copyFormattingDesc = NULL,
189 .copyDebugDesc = _auth_item_copy_description
190 );
191
192 static CFTypeID auth_item_get_type_id() {
193 static CFTypeID type_id = _kCFRuntimeNotATypeID;
194 static dispatch_once_t onceToken;
195
196 dispatch_once(&onceToken, ^{
197 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_item);
198 });
199
200 return type_id;
201 }
202
203 static auth_item_t
204 _auth_item_create()
205 {
206 auth_item_t item = NULL;
207
208 item = (auth_item_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, auth_item_get_type_id(), AUTH_CLASS_SIZE(auth_item), NULL);
209 require(item != NULL, done);
210
211 done:
212 return item;
213 }
214
215 static auth_item_t
216 auth_item_create(uint32_t type, const char * name, const void * value, size_t valueLen, uint32_t flags)
217 {
218 auth_item_t item = NULL;
219 require(name != NULL, done);
220
221 item = _auth_item_create();
222 require(item != NULL, done);
223
224 item->type = type;
225 item->data.flags = flags;
226 item->data.name = _copy_string(name);
227 item->data.valueLength = valueLen;
228 item->bufLen = valueLen;
229 if (value) {
230 if (item->type == AI_TYPE_STRING) {
231 item->bufLen++;
232 item->data.value = calloc(1u, item->bufLen);
233 } else if (valueLen) {
234 item->data.value = calloc(1u, item->bufLen);
235 }
236 if (valueLen) {
237 memcpy(item->data.value, value, valueLen);
238 }
239 }
240
241 done:
242 return item;
243 }
244
245 static auth_item_t
246 auth_item_create_with_xpc(xpc_object_t data)
247 {
248 auth_item_t item = NULL;
249 require(data != NULL, done);
250 require(xpc_get_type(data) == XPC_TYPE_DICTIONARY, done);
251 require(xpc_dictionary_get_string(data, AUTH_XPC_ITEM_NAME) != NULL, done);
252
253 item = _auth_item_create();
254 require(item != NULL, done);
255
256 item->data.name = _copy_string(xpc_dictionary_get_string(data, AUTH_XPC_ITEM_NAME));
257 item->data.flags = (uint32_t)xpc_dictionary_get_uint64(data, AUTH_XPC_ITEM_FLAGS);
258 item->type = (uint32_t)xpc_dictionary_get_uint64(data, AUTH_XPC_ITEM_TYPE);
259
260 size_t len;
261 const void * value = xpc_dictionary_get_data(data, AUTH_XPC_ITEM_VALUE, &len);
262 if (value) {
263 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
264 bool sensitive = xpc_dictionary_get_value(data, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH);
265 if (sensitive) {
266 size_t sensitiveLength = (size_t)xpc_dictionary_get_uint64(data, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH);
267 item->bufLen = sensitiveLength;
268 item->data.valueLength = sensitiveLength;
269 item->data.value = calloc(1u, sensitiveLength);
270 memcpy(item->data.value, value, sensitiveLength);
271 memset_s((void *)value, len, 0, sensitiveLength); // clear the sensitive data, memset_s is never optimized away
272 } else {
273 item->bufLen = len;
274 item->data.valueLength = len;
275 item->data.value = calloc(1u, len);
276 memcpy(item->data.value, value, len);
277 }
278 }
279
280 done:
281 return item;
282 }
283
284 #pragma mark -
285 #pragma mark auth_items_t
286
287 struct _auth_items_s {
288 __AUTH_BASE_STRUCT_HEADER__;
289
290 CFMutableDictionaryRef dictionary;
291 AuthorizationItemSet set;
292 };
293
294 static void
295 _auth_items_finalize(CFTypeRef value)
296 {
297 auth_items_t items = (auth_items_t)value;
298
299 CFReleaseNull(items->dictionary);
300 free_safe(items->set.items)
301 }
302
303 static Boolean
304 _auth_items_equal(CFTypeRef value1, CFTypeRef value2)
305 {
306 auth_items_t items1 = (auth_items_t)value1;
307 auth_items_t items2 = (auth_items_t)value2;
308
309 return CFEqual(items1->dictionary, items2->dictionary);
310 }
311
312 static CFStringRef
313 _auth_items_copy_description(CFTypeRef value)
314 {
315 auth_items_t items = (auth_items_t)value;
316 return CFCopyDescription(items->dictionary);
317 }
318
319 AUTH_TYPE_INSTANCE(auth_items,
320 .init = NULL,
321 .copy = NULL,
322 .finalize = _auth_items_finalize,
323 .equal = _auth_items_equal,
324 .hash = NULL,
325 .copyFormattingDesc = NULL,
326 .copyDebugDesc = _auth_items_copy_description
327 );
328
329 CFTypeID auth_items_get_type_id()
330 {
331 static CFTypeID type_id = _kCFRuntimeNotATypeID;
332 static dispatch_once_t onceToken;
333
334 dispatch_once(&onceToken, ^{
335 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_items);
336 });
337
338 return type_id;
339 }
340
341 static auth_items_t
342 _auth_items_create(bool createDict)
343 {
344 auth_items_t items = NULL;
345
346 items = (auth_items_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, auth_items_get_type_id(), AUTH_CLASS_SIZE(auth_items), NULL);
347 require(items != NULL, done);
348
349 if (createDict) {
350 items->dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
351 }
352
353 done:
354 return items;
355 }
356
357 auth_items_t
358 auth_items_create()
359 {
360 auth_items_t items = NULL;
361
362 items = _auth_items_create(true);
363 require(items != NULL, done);
364
365 done:
366 return items;
367 }
368
369 static bool
370 _auth_items_parse_xpc(auth_items_t items, const xpc_object_t data)
371 {
372 bool result = false;
373 require(data != NULL, done);
374 require(xpc_get_type(data) == XPC_TYPE_ARRAY, done);
375
376 result = xpc_array_apply(data, ^bool(size_t index AUTH_UNUSED, xpc_object_t value) {
377
378 auth_item_t item = auth_item_create_with_xpc(value);
379 if (item) {
380 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
381 CFReleaseSafe(item);
382 }
383
384 return true;
385 });
386
387 done:
388 return result;
389 }
390
391 auth_items_t auth_items_create_with_xpc(const xpc_object_t data)
392 {
393 auth_items_t items = NULL;
394
395 items = _auth_items_create(true);
396 require(items != NULL, done);
397
398 _auth_items_parse_xpc(items, data);
399
400 done:
401 return items;
402 }
403
404 auth_items_t
405 auth_items_create_copy(auth_items_t copy)
406 {
407 auth_items_t items = NULL;
408
409 items = _auth_items_create(false);
410 require(items != NULL, done);
411
412 items->dictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(copy->dictionary), copy->dictionary);
413
414 done:
415 return items;
416 }
417
418 size_t
419 auth_items_get_count(auth_items_t items)
420 {
421 return (size_t)CFDictionaryGetCount(items->dictionary);
422 }
423
424 AuthorizationItemSet *
425 auth_items_get_item_set(auth_items_t items)
426 {
427 uint32_t count = (uint32_t)CFDictionaryGetCount(items->dictionary);
428 if (count) {
429 size_t size = count * sizeof(AuthorizationItem);
430 if (items->set.items == NULL) {
431 items->set.items = calloc(1u, size);
432 require(items->set.items != NULL, done);
433 } else {
434 if (count > items->set.count) {
435 items->set.items = realloc(items->set.items, size);
436 require_action(items->set.items != NULL, done, items->set.count = 0);
437 }
438 }
439 items->set.count = count;
440 CFTypeRef keys[count], values[count];
441 CFDictionaryGetKeysAndValues(items->dictionary, keys, values);
442 for (uint32_t i = 0; i < count; i++) {
443 auth_item_t item = (auth_item_t)values[i];
444 items->set.items[i] = *auth_item_get_auth_item(item);
445 }
446 } else {
447 items->set.count = 0;
448 }
449
450 done:
451 return &items->set;
452 }
453
454 xpc_object_t
455 auth_items_export_xpc(auth_items_t items)
456 {
457 xpc_object_t array = xpc_array_create(NULL, 0);
458
459 _cf_dictionary_iterate(items->dictionary, ^bool(CFTypeRef key AUTH_UNUSED, CFTypeRef value) {
460 auth_item_t item = (auth_item_t)value;
461 xpc_object_t xpc_data = auth_item_copy_auth_item_xpc(item);
462 xpc_array_append_value(array, xpc_data);
463 xpc_release_safe(xpc_data);
464 return true;
465 });
466
467 return array;
468 }
469
470 static auth_item_t
471 _find_item(auth_items_t items, const char * key)
472 {
473 auth_item_t item = NULL;
474 CFStringRef lookup = NULL;
475 require(key != NULL, done);
476
477 lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
478 require(lookup != NULL, done);
479
480 item = (auth_item_t)CFDictionaryGetValue(items->dictionary, lookup);
481
482 done:
483 CFReleaseSafe(lookup);
484 return item;
485 }
486
487 void
488 auth_items_set_flags(auth_items_t items, const char *key, uint32_t flags)
489 {
490 auth_item_t item = _find_item(items,key);
491 if (item) {
492 item->data.flags |= flags;
493 }
494 }
495
496 void
497 auth_items_clear_flags(auth_items_t items, const char *key, uint32_t flags)
498 {
499 auth_item_t item = _find_item(items,key);
500 if (item) {
501 item->data.flags &= ~flags;
502 }
503 }
504
505 uint32_t
506 auth_items_get_flags(auth_items_t items, const char *key)
507 {
508 auth_item_t item = _find_item(items,key);
509 if (item) {
510 return item->data.flags;
511 }
512
513 return 0;
514 }
515
516 bool
517 auth_items_check_flags(auth_items_t items, const char *key, uint32_t flags)
518 {
519 // When several bits are set in uint32_t flags, "(current & flags) != 0" checks if ANY flag is set, not all flags!
520 // This odd behavior is currently being relied upon in several places, so be careful when changing / fixing this.
521 // However, this also risks unwanted information leakage in
522 // AuthorizationCopyInfo ==> authorization_copy_info ==> [all info] auth_items_copy_with_flags
523 uint32_t current = auth_items_get_flags(items,key);
524 return flags ? (current & flags) != 0 : current == 0;
525 }
526
527 void
528 auth_items_set_key(auth_items_t items, const char *key)
529 {
530 auth_item_t item = _find_item(items,key);
531 if (!item) {
532 item = auth_item_create(AI_TYPE_RIGHT, key, NULL, 0, 0);
533 if (item) {
534 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
535 CFReleaseSafe(item);
536 }
537 }
538 }
539
540 bool
541 auth_items_exist(auth_items_t items, const char *key)
542 {
543 return _find_item(items,key) != NULL;
544 }
545
546 void
547 auth_items_remove(auth_items_t items, const char *key)
548 {
549 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
550 CFDictionaryRemoveValue(items->dictionary, lookup);
551 CFReleaseSafe(lookup);
552 }
553
554 void
555 auth_items_remove_with_flags(auth_items_t items, uint32_t flags)
556 {
557 auth_items_iterate(items, ^bool(const char *key) {
558 if (auth_items_check_flags(items, key, flags)) {
559 auth_items_remove(items,key);
560 }
561 return true;
562 });
563 }
564
565 void
566 auth_items_clear(auth_items_t items)
567 {
568 CFDictionaryRemoveAllValues(items->dictionary);
569 }
570
571 void
572 auth_items_copy(auth_items_t items, auth_items_t src)
573 {
574 auth_items_iterate(src, ^bool(const char *key) {
575 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
576 auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup);
577 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
578 CFReleaseSafe(lookup);
579 return true;
580 });
581 }
582
583 void
584 auth_items_copy_xpc(auth_items_t items, const xpc_object_t src)
585 {
586 _auth_items_parse_xpc(items,src);
587 }
588
589 void
590 auth_items_copy_with_flags(auth_items_t items, auth_items_t src, uint32_t flags)
591 {
592 auth_items_iterate(src, ^bool(const char *key) {
593 if (auth_items_check_flags(src, key, flags)) {
594 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
595 auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup);
596 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
597 CFReleaseSafe(lookup);
598 }
599 return true;
600 });
601 }
602
603 bool
604 auth_items_iterate(auth_items_t items, auth_items_iterator_t iter)
605 {
606 bool result = false;
607 CFTypeRef* keys = NULL;
608 CFTypeRef* values = NULL;
609
610 CFIndex count = CFDictionaryGetCount(items->dictionary);
611 keys = calloc((size_t)count, sizeof(CFTypeRef));
612 require(keys != NULL, done);
613
614 values = calloc((size_t)count, sizeof(CFTypeRef));
615 require(values != NULL, done);
616
617 CFDictionaryGetKeysAndValues(items->dictionary, keys, values);
618 for (CFIndex i = 0; i < count; i++) {
619 auth_item_t item = (auth_item_t)values[i];
620 result = iter(item->data.name);
621 if (!result) {
622 break;
623 }
624 }
625
626 done:
627 free_safe(keys);
628 free_safe(values);
629 return result;
630 }
631
632 void
633 auth_items_set_string(auth_items_t items, const char *key, const char *value)
634 {
635 assert(value); // marked non-null
636
637 size_t valLen = strlen(value);
638 auth_item_t item = _find_item(items,key);
639 if (item && item->type == AI_TYPE_STRING && valLen < item->bufLen) {
640 memcpy(item->data.value, value, valLen+1); // copy null
641 item->data.valueLength = valLen;
642 } else {
643 item = auth_item_create(AI_TYPE_STRING, key, value, valLen, 0);
644 if (item) {
645 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
646 CFReleaseSafe(item);
647 }
648 }
649 }
650
651 const char *
652 auth_items_get_string(auth_items_t items, const char *key)
653 {
654 auth_item_t item = _find_item(items,key);
655 if (item) {
656 #if DEBUG
657 if (!(item->type == AI_TYPE_STRING || item->type == AI_TYPE_UNKNOWN)) {
658 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
659 item->data.name, item->type, AI_TYPE_STRING);
660 }
661 #endif
662 return auth_item_get_string(item);
663 }
664
665 return NULL;
666 }
667
668 void
669 auth_items_set_data(auth_items_t items, const char *key, const void *value, size_t len)
670 {
671 assert(value); // marked non-null
672
673 if (len) {
674 auth_item_t item = _find_item(items,key);
675 if (item && item->type == AI_TYPE_DATA && len <= item->bufLen) {
676 memcpy(item->data.value, value, len);
677 item->data.valueLength = len;
678 } else {
679 item = auth_item_create(AI_TYPE_DATA, key, value, len, 0);
680 if (item) {
681 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
682 CFReleaseSafe(item);
683 }
684 }
685 }
686 }
687
688 const void *
689 auth_items_get_data(auth_items_t items, const char *key, size_t *len)
690 {
691 assert(len); // marked non-null
692
693 auth_item_t item = _find_item(items,key);
694 if (item) {
695 #if DEBUG
696 if (!(item->type == AI_TYPE_DATA || item->type == AI_TYPE_UNKNOWN)) {
697 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
698 item->data.name, item->type, AI_TYPE_DATA);
699 }
700 #endif
701 *len = item->data.valueLength;
702 return item->data.value;
703 }
704
705 return NULL;
706 }
707
708 const void *
709 auth_items_get_data_with_flags(auth_items_t items, const char *key, size_t *len, uint32_t flags)
710 {
711 assert(len); // marked non-null
712
713 auth_item_t item = _find_item(items,key);
714 if (item && (item->data.flags & flags) == flags) {
715 #if DEBUG
716 if (!(item->type == AI_TYPE_DATA || item->type == AI_TYPE_UNKNOWN)) {
717 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
718 item->data.name, item->type, AI_TYPE_DATA);
719 }
720 #endif
721 *len = item->data.valueLength;
722
723 return item->data.value;
724 }
725
726 return NULL;
727 }
728
729 void
730 auth_items_set_bool(auth_items_t items, const char *key, bool value)
731 {
732 auth_item_t item = _find_item(items,key);
733 if (item && item->type == AI_TYPE_BOOL) {
734 *(bool*)item->data.value = value;
735 } else {
736 item = auth_item_create(AI_TYPE_BOOL, key, &value, sizeof(bool), 0);
737 if (item) {
738 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
739 CFReleaseSafe(item);
740 }
741 }
742 }
743
744 bool
745 auth_items_get_bool(auth_items_t items, const char *key)
746 {
747 auth_item_t item = _find_item(items,key);
748 if (item) {
749 #if DEBUG
750 if (!(item->type == AI_TYPE_BOOL || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(bool))) {
751 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
752 item->data.name, item->type, AI_TYPE_BOOL, item->data.valueLength, sizeof(bool));
753 }
754 #endif
755 if (item->type == AI_TYPE_STRING) {
756 return atoi(auth_item_get_string(item));
757 }
758
759 require(item->data.value != NULL, done);
760 require(item->data.valueLength == sizeof(bool), done);
761
762 return *(bool*)item->data.value;
763 }
764
765 done:
766 return false;
767 }
768
769 void
770 auth_items_set_int(auth_items_t items, const char *key, int32_t value)
771 {
772 auth_item_t item = _find_item(items,key);
773 if (item && item->type == AI_TYPE_INT) {
774 *(int32_t*)item->data.value = value;
775 } else {
776 item = auth_item_create(AI_TYPE_INT, key, &value, sizeof(int32_t), 0);
777 if (item) {
778 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
779 CFReleaseSafe(item);
780 }
781 }
782 }
783
784 int32_t
785 auth_items_get_int(auth_items_t items, const char *key)
786 {
787 auth_item_t item = _find_item(items,key);
788 if (item) {
789 #if DEBUG
790 if (!(item->type ==AI_TYPE_INT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int32_t))) {
791 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
792 item->data.name, item->type, AI_TYPE_INT, item->data.valueLength, sizeof(int32_t));
793 }
794 #endif
795 if (item->type == AI_TYPE_STRING) {
796 return atoi(auth_item_get_string(item));
797 }
798
799 require(item->data.value != NULL, done);
800 require(item->data.valueLength == sizeof(int32_t), done);
801
802 return *(int32_t*)item->data.value;
803 }
804
805 done:
806 return 0;
807 }
808
809 void
810 auth_items_set_uint(auth_items_t items, const char *key, uint32_t value)
811 {
812 auth_item_t item = _find_item(items,key);
813 if (item && item->type == AI_TYPE_UINT) {
814 *(uint32_t*)item->data.value = value;
815 } else {
816 item = auth_item_create(AI_TYPE_UINT, key, &value, sizeof(uint32_t), 0);
817 if (item) {
818 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
819 CFReleaseSafe(item);
820 }
821 }
822 }
823
824 uint32_t
825 auth_items_get_uint(auth_items_t items, const char *key)
826 {
827 auth_item_t item = _find_item(items,key);
828 if (item) {
829 #if DEBUG
830 if (!(item->type ==AI_TYPE_UINT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint32_t))) {
831 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
832 item->data.name, item->type, AI_TYPE_UINT, item->data.valueLength, sizeof(uint32_t));
833 }
834 #endif
835 if (item->type == AI_TYPE_STRING) {
836 return (uint32_t)atoi(auth_item_get_string(item));
837 }
838
839 require(item->data.value != NULL, done);
840 require(item->data.valueLength == sizeof(uint32_t), done);
841
842 return *(uint32_t*)item->data.value;
843 }
844
845 done:
846 return 0;
847 }
848
849 void
850 auth_items_set_int64(auth_items_t items, const char *key, int64_t value)
851 {
852 auth_item_t item = _find_item(items,key);
853 if (item && item->type == AI_TYPE_INT64) {
854 *(int64_t*)item->data.value = value;
855 } else {
856 item = auth_item_create(AI_TYPE_INT64, key, &value, sizeof(int64_t), 0);
857 if (item) {
858 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
859 CFReleaseSafe(item);
860 }
861 }
862 }
863
864 int64_t
865 auth_items_get_int64(auth_items_t items, const char *key)
866 {
867 auth_item_t item = _find_item(items,key);
868 if (item) {
869 #if DEBUG
870 if (!(item->type ==AI_TYPE_INT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int64_t))) {
871 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
872 item->data.name, item->type, AI_TYPE_INT64, item->data.valueLength, sizeof(int64_t));
873 }
874 #endif
875 if (item->type == AI_TYPE_STRING) {
876 return atoll(auth_item_get_string(item));
877 }
878
879 require(item->data.value != NULL, done);
880 require(item->data.valueLength == sizeof(int64_t), done);
881
882 return *(int64_t*)item->data.value;
883 }
884
885 done:
886 return 0;
887 }
888
889 void
890 auth_items_set_uint64(auth_items_t items, const char *key, uint64_t value)
891 {
892 auth_item_t item = _find_item(items,key);
893 if (item && item->type == AI_TYPE_UINT64) {
894 *(uint64_t*)item->data.value = value;
895 } else {
896 item = auth_item_create(AI_TYPE_UINT64, key, &value, sizeof(uint64_t), 0);
897 if (item) {
898 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
899 CFReleaseSafe(item);
900 }
901 }
902 }
903
904 uint64_t
905 auth_items_get_uint64(auth_items_t items, const char *key)
906 {
907 auth_item_t item = _find_item(items,key);
908 if (item) {
909 #if DEBUG
910 if (!(item->type ==AI_TYPE_UINT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint64_t))) {
911 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
912 item->data.name, item->type, AI_TYPE_UINT64, item->data.valueLength, sizeof(uint64_t));
913 }
914 #endif
915 if (item->type == AI_TYPE_STRING) {
916 return (uint64_t)atoll(auth_item_get_string(item));
917 }
918
919 require(item->data.value != NULL, done);
920 require(item->data.valueLength == sizeof(uint64_t), done);
921
922 return *(uint64_t*)item->data.value;
923 }
924
925 done:
926 return 0;
927 }
928
929 void auth_items_set_double(auth_items_t items, const char *key, double value)
930 {
931 auth_item_t item = _find_item(items,key);
932 if (item && item->type == AI_TYPE_DOUBLE) {
933 *(double*)item->data.value = value;
934 } else {
935 item = auth_item_create(AI_TYPE_DOUBLE, key, &value, sizeof(double), 0);
936 if (item) {
937 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
938 CFReleaseSafe(item);
939 }
940 }
941 }
942
943 double auth_items_get_double(auth_items_t items, const char *key)
944 {
945 auth_item_t item = _find_item(items,key);
946 if (item) {
947 #if DEBUG
948 if (!(item->type ==AI_TYPE_DOUBLE || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(double))) {
949 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
950 item->data.name, item->type, AI_TYPE_DOUBLE, item->data.valueLength, sizeof(double));
951 }
952 #endif
953 if (item->type == AI_TYPE_STRING) {
954 return atof(auth_item_get_string(item));
955 }
956
957 require(item->data.value != NULL, done);
958 require(item->data.valueLength == sizeof(double), done);
959
960 return *(double*)item->data.value;
961 }
962
963 done:
964 return 0;
965 }
966
967 uint32_t auth_items_get_type(auth_items_t items, const char *key)
968 {
969 auth_item_t item = _find_item(items,key);
970 if (item) {
971 return item->type;
972 }
973
974 return AI_TYPE_UNKNOWN;
975 }
976
977 size_t auth_items_get_length(auth_items_t items, const char *key)
978 {
979 auth_item_t item = _find_item(items,key);
980 if (item) {
981 return item->data.valueLength;
982 }
983
984 return 0;
985 }
986
987 void auth_items_set_value(auth_items_t items, const char *key, uint32_t type, uint32_t flags, const void *value, size_t len)
988 {
989 auth_item_t item = auth_item_create(type, key, value, len, flags);
990 if (item) {
991 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
992 CFReleaseSafe(item);
993 }
994 }
995
996 #pragma mark -
997 #pragma mark auth_rights_t
998
999 struct _auth_rights_s {
1000 __AUTH_BASE_STRUCT_HEADER__;
1001
1002 CFMutableArrayRef array;
1003 };
1004
1005 static void
1006 _auth_rights_finalize(CFTypeRef value)
1007 {
1008 auth_rights_t rights = (auth_rights_t)value;
1009
1010 CFReleaseNull(rights->array);
1011 }
1012
1013 static Boolean
1014 _auth_rights_equal(CFTypeRef value1, CFTypeRef value2)
1015 {
1016 auth_rights_t rights1 = (auth_rights_t)value1;
1017 auth_rights_t rights2 = (auth_rights_t)value2;
1018
1019 return CFEqual(rights1->array, rights2->array);
1020 }
1021
1022 static CFStringRef
1023 _auth_rights_copy_description(CFTypeRef value)
1024 {
1025 auth_rights_t rights = (auth_rights_t)value;
1026 return CFCopyDescription(rights->array);
1027 }
1028
1029 AUTH_TYPE_INSTANCE(auth_rights,
1030 .init = NULL,
1031 .copy = NULL,
1032 .finalize = _auth_rights_finalize,
1033 .equal = _auth_rights_equal,
1034 .hash = NULL,
1035 .copyFormattingDesc = NULL,
1036 .copyDebugDesc = _auth_rights_copy_description
1037 );
1038
1039 static CFTypeID auth_rights_get_type_id()
1040 {
1041 static CFTypeID type_id = _kCFRuntimeNotATypeID;
1042 static dispatch_once_t onceToken;
1043
1044 dispatch_once(&onceToken, ^{
1045 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_rights);
1046 });
1047
1048 return type_id;
1049 }
1050
1051 static auth_rights_t
1052 _auth_rights_create()
1053 {
1054 auth_rights_t rights = NULL;
1055
1056 rights = (auth_rights_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights), NULL);
1057 require(rights != NULL, done);
1058
1059 rights->array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1060
1061 done:
1062 return rights;
1063 }
1064
1065 auth_rights_t
1066 auth_rights_create()
1067 {
1068 auth_rights_t rights = _auth_rights_create();
1069 require(rights != NULL, done);
1070
1071 done:
1072 return rights;
1073 }
1074
1075 auth_rights_t auth_rights_create_with_xpc(const xpc_object_t data)
1076 {
1077 auth_rights_t rights = _auth_rights_create();
1078 require(rights != NULL, done);
1079 require(data != NULL, done);
1080 require(xpc_get_type(data) == XPC_TYPE_ARRAY, done);
1081
1082 xpc_array_apply(data, ^bool(size_t index AUTH_UNUSED, xpc_object_t value) {
1083
1084 auth_item_t item = auth_item_create_with_xpc(value);
1085 if (item) {
1086 CFArrayAppendValue(rights->array, item);
1087 CFReleaseSafe(item);
1088 }
1089
1090 return true;
1091 });
1092
1093 done:
1094 return rights;
1095 }
1096
1097 xpc_object_t auth_rights_export_xpc(auth_rights_t rights)
1098 {
1099 xpc_object_t array = xpc_array_create(NULL, 0);
1100
1101 CFIndex count = CFArrayGetCount(rights->array);
1102 for (CFIndex i = 0; i < count; i++) {
1103 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1104 xpc_object_t xpc_data = auth_item_copy_auth_item_xpc(item);
1105 xpc_array_append_value(array, xpc_data);
1106 xpc_release_safe(xpc_data);
1107 }
1108
1109 return array;
1110 }
1111
1112 static auth_item_t
1113 _find_right_item(auth_rights_t rights, const char * key)
1114 {
1115 auth_item_t item = NULL;
1116 CFStringRef lookup = NULL;
1117 require(key != NULL, done);
1118
1119 lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
1120 require(lookup != NULL, done);
1121
1122 CFIndex count = CFArrayGetCount(rights->array);
1123 for (CFIndex i = 0; i < count; i++) {
1124 auth_item_t tmp = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1125 if (tmp && CFEqual(auth_item_get_cf_key(tmp), lookup)) {
1126 item = tmp;
1127 break;
1128 }
1129 }
1130
1131 done:
1132 CFReleaseSafe(lookup);
1133 return item;
1134 }
1135
1136 void auth_rights_set_flags(auth_rights_t rights, const char *key, uint32_t flags)
1137 {
1138 auth_item_t item = _find_right_item(rights,key);
1139 if (item) {
1140 item->data.flags |= flags;
1141 }
1142 }
1143
1144 void auth_rights_clear_flags(auth_rights_t rights, const char *key, uint32_t flags)
1145 {
1146 auth_item_t item = _find_right_item(rights,key);
1147 if (item) {
1148 item->data.flags &= ~flags;
1149 }
1150 }
1151
1152 uint32_t auth_rights_get_flags(auth_rights_t rights, const char *key)
1153 {
1154 auth_item_t item = _find_right_item(rights,key);
1155 if (item) {
1156 return item->data.flags;
1157 }
1158
1159 return 0;
1160 }
1161
1162 bool auth_rights_check_flags(auth_rights_t rights, const char *key, uint32_t flags)
1163 {
1164 uint32_t current = auth_rights_get_flags(rights,key);
1165 return flags ? (current & flags) != 0 : current == 0;
1166 }
1167
1168 size_t auth_rights_get_count(auth_rights_t rights)
1169 {
1170 return (size_t)CFArrayGetCount(rights->array);
1171 }
1172
1173 void auth_rights_add(auth_rights_t rights, const char *key)
1174 {
1175 auth_item_t item = auth_item_create(AI_TYPE_RIGHT, key, NULL, 0, 0);
1176 if (item) {
1177 CFArrayAppendValue(rights->array, item);
1178 CFReleaseSafe(item);
1179 }
1180 }
1181
1182 bool auth_rights_exist(auth_rights_t rights, const char *key)
1183 {
1184 return (_find_right_item(rights,key) != NULL);
1185 }
1186
1187 void auth_rights_remove(auth_rights_t rights, const char *key)
1188 {
1189 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
1190 CFIndex count = CFArrayGetCount(rights->array);
1191 for (CFIndex i = 0; i < count; i++) {
1192 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1193 if (CFEqual(auth_item_get_cf_key(item), lookup)) {
1194 CFArrayRemoveValueAtIndex(rights->array, i);
1195 i--;
1196 count--;
1197 }
1198 }
1199 CFReleaseSafe(lookup);
1200 }
1201
1202 void auth_rights_clear(auth_rights_t rights)
1203 {
1204 CFArrayRemoveAllValues(rights->array);
1205 }
1206
1207 bool
1208 auth_rights_iterate(auth_rights_t rights, bool(^iter)(const char * key))
1209 {
1210 bool result = false;
1211
1212 CFIndex count = CFArrayGetCount(rights->array);
1213 for (CFIndex i = 0; i < count; i++) {
1214 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1215 result = iter(item->data.name);
1216 if (!result) {
1217 break;
1218 }
1219 }
1220
1221 return result;
1222 }