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