]> git.saurik.com Git - apple/security.git/blob - OSX/authd/authitems.c
Security-57740.1.18.tar.gz
[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
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, (unsigned int)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 (CFHashCode)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 (uint32_t 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 // When several bits are set in uint32_t flags, "(current & flags) != 0" checks if ANY flag is set, not all flags!
493 // This odd behavior is currently being relied upon in several places, so be careful when changing / fixing this.
494 // However, this also risks unwanted information leakage in
495 // AuthorizationCopyInfo ==> authorization_copy_info ==> [all info] auth_items_copy_with_flags
496 uint32_t current = auth_items_get_flags(items,key);
497 return flags ? (current & flags) != 0 : current == 0;
498 }
499
500 void
501 auth_items_set_key(auth_items_t items, const char *key)
502 {
503 auth_item_t item = _find_item(items,key);
504 if (!item) {
505 item = auth_item_create(AI_TYPE_RIGHT, key, NULL, 0, 0);
506 if (item) {
507 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
508 CFReleaseSafe(item);
509 }
510 }
511 }
512
513 bool
514 auth_items_exist(auth_items_t items, const char *key)
515 {
516 return _find_item(items,key) != NULL;
517 }
518
519 void
520 auth_items_remove(auth_items_t items, const char *key)
521 {
522 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
523 CFDictionaryRemoveValue(items->dictionary, lookup);
524 CFReleaseSafe(lookup);
525 }
526
527 void
528 auth_items_remove_with_flags(auth_items_t items, uint32_t flags)
529 {
530 auth_items_iterate(items, ^bool(const char *key) {
531 if (auth_items_check_flags(items, key, flags)) {
532 auth_items_remove(items,key);
533 }
534 return true;
535 });
536 }
537
538 void
539 auth_items_clear(auth_items_t items)
540 {
541 CFDictionaryRemoveAllValues(items->dictionary);
542 }
543
544 void
545 auth_items_copy(auth_items_t items, auth_items_t src)
546 {
547 auth_items_iterate(src, ^bool(const char *key) {
548 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
549 auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup);
550 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
551 CFReleaseSafe(lookup);
552 return true;
553 });
554 }
555
556 void
557 auth_items_copy_xpc(auth_items_t items, const xpc_object_t src)
558 {
559 _auth_items_parse_xpc(items,src);
560 }
561
562 void
563 auth_items_copy_with_flags(auth_items_t items, auth_items_t src, uint32_t flags)
564 {
565 auth_items_iterate(src, ^bool(const char *key) {
566 if (auth_items_check_flags(src, key, flags)) {
567 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
568 auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup);
569 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
570 CFReleaseSafe(lookup);
571 }
572 return true;
573 });
574 }
575
576 bool
577 auth_items_iterate(auth_items_t items, auth_items_iterator_t iter)
578 {
579 bool result = false;
580 CFTypeRef* keys = NULL;
581 CFTypeRef* values = NULL;
582
583 CFIndex count = CFDictionaryGetCount(items->dictionary);
584 keys = calloc((size_t)count, sizeof(CFTypeRef));
585 require(keys != NULL, done);
586
587 values = calloc((size_t)count, sizeof(CFTypeRef));
588 require(values != NULL, done);
589
590 CFDictionaryGetKeysAndValues(items->dictionary, keys, values);
591 for (CFIndex i = 0; i < count; i++) {
592 auth_item_t item = (auth_item_t)values[i];
593 result = iter(item->data.name);
594 if (!result) {
595 break;
596 }
597 }
598
599 done:
600 free_safe(keys);
601 free_safe(values);
602 return result;
603 }
604
605 void
606 auth_items_set_string(auth_items_t items, const char *key, const char *value)
607 {
608 assert(value); // marked non-null
609
610 size_t valLen = strlen(value);
611 auth_item_t item = _find_item(items,key);
612 if (item && item->type == AI_TYPE_STRING && valLen < item->bufLen) {
613 memcpy(item->data.value, value, valLen+1); // copy null
614 item->data.valueLength = valLen;
615 } else {
616 item = auth_item_create(AI_TYPE_STRING, key, value, valLen, 0);
617 if (item) {
618 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
619 CFReleaseSafe(item);
620 }
621 }
622 }
623
624 const char *
625 auth_items_get_string(auth_items_t items, const char *key)
626 {
627 auth_item_t item = _find_item(items,key);
628 if (item) {
629 #if DEBUG
630 if (!(item->type == AI_TYPE_STRING || item->type == AI_TYPE_UNKNOWN)) {
631 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
632 item->data.name, item->type, AI_TYPE_STRING);
633 }
634 #endif
635 return auth_item_get_string(item);
636 }
637
638 return NULL;
639 }
640
641 void
642 auth_items_set_data(auth_items_t items, const char *key, const void *value, size_t len)
643 {
644 assert(value); // marked non-null
645
646 if (len) {
647 auth_item_t item = _find_item(items,key);
648 if (item && item->type == AI_TYPE_DATA && len <= item->bufLen) {
649 memcpy(item->data.value, value, len);
650 item->data.valueLength = len;
651 } else {
652 item = auth_item_create(AI_TYPE_DATA, key, value, len, 0);
653 if (item) {
654 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
655 CFReleaseSafe(item);
656 }
657 }
658 }
659 }
660
661 const void *
662 auth_items_get_data(auth_items_t items, const char *key, size_t *len)
663 {
664 assert(len); // marked non-null
665
666 auth_item_t item = _find_item(items,key);
667 if (item) {
668 #if DEBUG
669 if (!(item->type == AI_TYPE_DATA || item->type == AI_TYPE_UNKNOWN)) {
670 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
671 item->data.name, item->type, AI_TYPE_DATA);
672 }
673 #endif
674 *len = item->data.valueLength;
675 return item->data.value;
676 }
677
678 return NULL;
679 }
680
681 const void *
682 auth_items_get_data_with_flags(auth_items_t items, const char *key, size_t *len, uint32_t flags)
683 {
684 assert(len); // marked non-null
685
686 auth_item_t item = _find_item(items,key);
687 if (item && (item->data.flags & flags) == flags) {
688 #if DEBUG
689 if (!(item->type == AI_TYPE_DATA || item->type == AI_TYPE_UNKNOWN)) {
690 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
691 item->data.name, item->type, AI_TYPE_DATA);
692 }
693 #endif
694 *len = item->data.valueLength;
695
696 return item->data.value;
697 }
698
699 return NULL;
700 }
701
702 void
703 auth_items_set_bool(auth_items_t items, const char *key, bool value)
704 {
705 auth_item_t item = _find_item(items,key);
706 if (item && item->type == AI_TYPE_BOOL) {
707 *(bool*)item->data.value = value;
708 } else {
709 item = auth_item_create(AI_TYPE_BOOL, key, &value, sizeof(bool), 0);
710 if (item) {
711 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
712 CFReleaseSafe(item);
713 }
714 }
715 }
716
717 bool
718 auth_items_get_bool(auth_items_t items, const char *key)
719 {
720 auth_item_t item = _find_item(items,key);
721 if (item) {
722 #if DEBUG
723 if (!(item->type == AI_TYPE_BOOL || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(bool))) {
724 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
725 item->data.name, item->type, AI_TYPE_BOOL, item->data.valueLength, sizeof(bool));
726 }
727 #endif
728 if (item->type == AI_TYPE_STRING) {
729 return atoi(auth_item_get_string(item));
730 }
731
732 require(item->data.value != NULL, done);
733 require(item->data.valueLength == sizeof(bool), done);
734
735 return *(bool*)item->data.value;
736 }
737
738 done:
739 return false;
740 }
741
742 void
743 auth_items_set_int(auth_items_t items, const char *key, int32_t value)
744 {
745 auth_item_t item = _find_item(items,key);
746 if (item && item->type == AI_TYPE_INT) {
747 *(int32_t*)item->data.value = value;
748 } else {
749 item = auth_item_create(AI_TYPE_INT, key, &value, sizeof(int32_t), 0);
750 if (item) {
751 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
752 CFReleaseSafe(item);
753 }
754 }
755 }
756
757 int32_t
758 auth_items_get_int(auth_items_t items, const char *key)
759 {
760 auth_item_t item = _find_item(items,key);
761 if (item) {
762 #if DEBUG
763 if (!(item->type ==AI_TYPE_INT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int32_t))) {
764 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
765 item->data.name, item->type, AI_TYPE_INT, item->data.valueLength, sizeof(int32_t));
766 }
767 #endif
768 if (item->type == AI_TYPE_STRING) {
769 return atoi(auth_item_get_string(item));
770 }
771
772 require(item->data.value != NULL, done);
773 require(item->data.valueLength == sizeof(int32_t), done);
774
775 return *(int32_t*)item->data.value;
776 }
777
778 done:
779 return 0;
780 }
781
782 void
783 auth_items_set_uint(auth_items_t items, const char *key, uint32_t value)
784 {
785 auth_item_t item = _find_item(items,key);
786 if (item && item->type == AI_TYPE_UINT) {
787 *(uint32_t*)item->data.value = value;
788 } else {
789 item = auth_item_create(AI_TYPE_UINT, key, &value, sizeof(uint32_t), 0);
790 if (item) {
791 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
792 CFReleaseSafe(item);
793 }
794 }
795 }
796
797 uint32_t
798 auth_items_get_uint(auth_items_t items, const char *key)
799 {
800 auth_item_t item = _find_item(items,key);
801 if (item) {
802 #if DEBUG
803 if (!(item->type ==AI_TYPE_UINT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint32_t))) {
804 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
805 item->data.name, item->type, AI_TYPE_UINT, item->data.valueLength, sizeof(uint32_t));
806 }
807 #endif
808 if (item->type == AI_TYPE_STRING) {
809 return (uint32_t)atoi(auth_item_get_string(item));
810 }
811
812 require(item->data.value != NULL, done);
813 require(item->data.valueLength == sizeof(uint32_t), done);
814
815 return *(uint32_t*)item->data.value;
816 }
817
818 done:
819 return 0;
820 }
821
822 void
823 auth_items_set_int64(auth_items_t items, const char *key, int64_t value)
824 {
825 auth_item_t item = _find_item(items,key);
826 if (item && item->type == AI_TYPE_INT64) {
827 *(int64_t*)item->data.value = value;
828 } else {
829 item = auth_item_create(AI_TYPE_INT64, key, &value, sizeof(int64_t), 0);
830 if (item) {
831 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
832 CFReleaseSafe(item);
833 }
834 }
835 }
836
837 int64_t
838 auth_items_get_int64(auth_items_t items, const char *key)
839 {
840 auth_item_t item = _find_item(items,key);
841 if (item) {
842 #if DEBUG
843 if (!(item->type ==AI_TYPE_INT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int64_t))) {
844 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
845 item->data.name, item->type, AI_TYPE_INT64, item->data.valueLength, sizeof(int64_t));
846 }
847 #endif
848 if (item->type == AI_TYPE_STRING) {
849 return atoll(auth_item_get_string(item));
850 }
851
852 require(item->data.value != NULL, done);
853 require(item->data.valueLength == sizeof(int64_t), done);
854
855 return *(int64_t*)item->data.value;
856 }
857
858 done:
859 return 0;
860 }
861
862 void
863 auth_items_set_uint64(auth_items_t items, const char *key, uint64_t value)
864 {
865 auth_item_t item = _find_item(items,key);
866 if (item && item->type == AI_TYPE_UINT64) {
867 *(uint64_t*)item->data.value = value;
868 } else {
869 item = auth_item_create(AI_TYPE_UINT64, key, &value, sizeof(uint64_t), 0);
870 if (item) {
871 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
872 CFReleaseSafe(item);
873 }
874 }
875 }
876
877 uint64_t
878 auth_items_get_uint64(auth_items_t items, const char *key)
879 {
880 auth_item_t item = _find_item(items,key);
881 if (item) {
882 #if DEBUG
883 if (!(item->type ==AI_TYPE_UINT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint64_t))) {
884 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
885 item->data.name, item->type, AI_TYPE_UINT64, item->data.valueLength, sizeof(uint64_t));
886 }
887 #endif
888 if (item->type == AI_TYPE_STRING) {
889 return (uint64_t)atoll(auth_item_get_string(item));
890 }
891
892 require(item->data.value != NULL, done);
893 require(item->data.valueLength == sizeof(uint64_t), done);
894
895 return *(uint64_t*)item->data.value;
896 }
897
898 done:
899 return 0;
900 }
901
902 void auth_items_set_double(auth_items_t items, const char *key, double value)
903 {
904 auth_item_t item = _find_item(items,key);
905 if (item && item->type == AI_TYPE_DOUBLE) {
906 *(double*)item->data.value = value;
907 } else {
908 item = auth_item_create(AI_TYPE_DOUBLE, key, &value, sizeof(double), 0);
909 if (item) {
910 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
911 CFReleaseSafe(item);
912 }
913 }
914 }
915
916 double auth_items_get_double(auth_items_t items, const char *key)
917 {
918 auth_item_t item = _find_item(items,key);
919 if (item) {
920 #if DEBUG
921 if (!(item->type ==AI_TYPE_DOUBLE || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(double))) {
922 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
923 item->data.name, item->type, AI_TYPE_DOUBLE, item->data.valueLength, sizeof(double));
924 }
925 #endif
926 if (item->type == AI_TYPE_STRING) {
927 return atof(auth_item_get_string(item));
928 }
929
930 require(item->data.value != NULL, done);
931 require(item->data.valueLength == sizeof(double), done);
932
933 return *(double*)item->data.value;
934 }
935
936 done:
937 return 0;
938 }
939
940 uint32_t auth_items_get_type(auth_items_t items, const char *key)
941 {
942 auth_item_t item = _find_item(items,key);
943 if (item) {
944 return item->type;
945 }
946
947 return AI_TYPE_UNKNOWN;
948 }
949
950 size_t auth_items_get_length(auth_items_t items, const char *key)
951 {
952 auth_item_t item = _find_item(items,key);
953 if (item) {
954 return item->data.valueLength;
955 }
956
957 return 0;
958 }
959
960 void auth_items_set_value(auth_items_t items, const char *key, uint32_t type, uint32_t flags, const void *value, size_t len)
961 {
962 auth_item_t item = auth_item_create(type, key, value, len, flags);
963 if (item) {
964 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item);
965 CFReleaseSafe(item);
966 }
967 }
968
969 #pragma mark -
970 #pragma mark auth_rights_t
971
972 struct _auth_rights_s {
973 __AUTH_BASE_STRUCT_HEADER__;
974
975 CFMutableArrayRef array;
976 };
977
978 static void
979 _auth_rights_finalize(CFTypeRef value)
980 {
981 auth_rights_t rights = (auth_rights_t)value;
982
983 CFReleaseNull(rights->array);
984 }
985
986 static Boolean
987 _auth_rights_equal(CFTypeRef value1, CFTypeRef value2)
988 {
989 auth_rights_t rights1 = (auth_rights_t)value1;
990 auth_rights_t rights2 = (auth_rights_t)value2;
991
992 return CFEqual(rights1->array, rights2->array);
993 }
994
995 static CFStringRef
996 _auth_rights_copy_description(CFTypeRef value)
997 {
998 auth_rights_t rights = (auth_rights_t)value;
999 return CFCopyDescription(rights->array);
1000 }
1001
1002 AUTH_TYPE_INSTANCE(auth_rights,
1003 .init = NULL,
1004 .copy = NULL,
1005 .finalize = _auth_rights_finalize,
1006 .equal = _auth_rights_equal,
1007 .hash = NULL,
1008 .copyFormattingDesc = NULL,
1009 .copyDebugDesc = _auth_rights_copy_description
1010 );
1011
1012 static CFTypeID auth_rights_get_type_id()
1013 {
1014 static CFTypeID type_id = _kCFRuntimeNotATypeID;
1015 static dispatch_once_t onceToken;
1016
1017 dispatch_once(&onceToken, ^{
1018 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_rights);
1019 });
1020
1021 return type_id;
1022 }
1023
1024 static auth_rights_t
1025 _auth_rights_create()
1026 {
1027 auth_rights_t rights = NULL;
1028
1029 rights = (auth_rights_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights), NULL);
1030 require(rights != NULL, done);
1031
1032 rights->array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
1033
1034 done:
1035 return rights;
1036 }
1037
1038 auth_rights_t
1039 auth_rights_create()
1040 {
1041 auth_rights_t rights = _auth_rights_create();
1042 require(rights != NULL, done);
1043
1044 done:
1045 return rights;
1046 }
1047
1048 auth_rights_t auth_rights_create_with_xpc(const xpc_object_t data)
1049 {
1050 auth_rights_t rights = _auth_rights_create();
1051 require(rights != NULL, done);
1052 require(data != NULL, done);
1053 require(xpc_get_type(data) == XPC_TYPE_ARRAY, done);
1054
1055 xpc_array_apply(data, ^bool(size_t index AUTH_UNUSED, xpc_object_t value) {
1056
1057 auth_item_t item = auth_item_create_with_xpc(value);
1058 if (item) {
1059 CFArrayAppendValue(rights->array, item);
1060 CFReleaseSafe(item);
1061 }
1062
1063 return true;
1064 });
1065
1066 done:
1067 return rights;
1068 }
1069
1070 xpc_object_t auth_rights_export_xpc(auth_rights_t rights)
1071 {
1072 xpc_object_t array = xpc_array_create(NULL, 0);
1073
1074 CFIndex count = CFArrayGetCount(rights->array);
1075 for (CFIndex i = 0; i < count; i++) {
1076 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1077 xpc_object_t xpc_data = auth_item_copy_auth_item_xpc(item);
1078 xpc_array_append_value(array, xpc_data);
1079 xpc_release_safe(xpc_data);
1080 }
1081
1082 return array;
1083 }
1084
1085 static auth_item_t
1086 _find_right_item(auth_rights_t rights, const char * key)
1087 {
1088 auth_item_t item = NULL;
1089 CFStringRef lookup = NULL;
1090 require(key != NULL, done);
1091
1092 lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
1093 require(lookup != NULL, done);
1094
1095 CFIndex count = CFArrayGetCount(rights->array);
1096 for (CFIndex i = 0; i < count; i++) {
1097 auth_item_t tmp = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1098 if (tmp && CFEqual(auth_item_get_cf_key(tmp), lookup)) {
1099 item = tmp;
1100 break;
1101 }
1102 }
1103
1104 done:
1105 CFReleaseSafe(lookup);
1106 return item;
1107 }
1108
1109 void auth_rights_set_flags(auth_rights_t rights, const char *key, uint32_t flags)
1110 {
1111 auth_item_t item = _find_right_item(rights,key);
1112 if (item) {
1113 item->data.flags |= flags;
1114 }
1115 }
1116
1117 void auth_rights_clear_flags(auth_rights_t rights, const char *key, uint32_t flags)
1118 {
1119 auth_item_t item = _find_right_item(rights,key);
1120 if (item) {
1121 item->data.flags &= ~flags;
1122 }
1123 }
1124
1125 uint32_t auth_rights_get_flags(auth_rights_t rights, const char *key)
1126 {
1127 auth_item_t item = _find_right_item(rights,key);
1128 if (item) {
1129 return item->data.flags;
1130 }
1131
1132 return 0;
1133 }
1134
1135 bool auth_rights_check_flags(auth_rights_t rights, const char *key, uint32_t flags)
1136 {
1137 uint32_t current = auth_rights_get_flags(rights,key);
1138 return flags ? (current & flags) != 0 : current == 0;
1139 }
1140
1141 size_t auth_rights_get_count(auth_rights_t rights)
1142 {
1143 return (size_t)CFArrayGetCount(rights->array);
1144 }
1145
1146 void auth_rights_add(auth_rights_t rights, const char *key)
1147 {
1148 auth_item_t item = auth_item_create(AI_TYPE_RIGHT, key, NULL, 0, 0);
1149 if (item) {
1150 CFArrayAppendValue(rights->array, item);
1151 CFReleaseSafe(item);
1152 }
1153 }
1154
1155 bool auth_rights_exist(auth_rights_t rights, const char *key)
1156 {
1157 return (_find_right_item(rights,key) != NULL);
1158 }
1159
1160 void auth_rights_remove(auth_rights_t rights, const char *key)
1161 {
1162 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull);
1163 CFIndex count = CFArrayGetCount(rights->array);
1164 for (CFIndex i = 0; i < count; i++) {
1165 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1166 if (CFEqual(auth_item_get_cf_key(item), lookup)) {
1167 CFArrayRemoveValueAtIndex(rights->array, i);
1168 i--;
1169 count--;
1170 }
1171 }
1172 CFReleaseSafe(lookup);
1173 }
1174
1175 void auth_rights_clear(auth_rights_t rights)
1176 {
1177 CFArrayRemoveAllValues(rights->array);
1178 }
1179
1180 bool
1181 auth_rights_iterate(auth_rights_t rights, bool(^iter)(const char * key))
1182 {
1183 bool result = false;
1184
1185 CFIndex count = CFArrayGetCount(rights->array);
1186 for (CFIndex i = 0; i < count; i++) {
1187 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i);
1188 result = iter(item->data.name);
1189 if (!result) {
1190 break;
1191 }
1192 }
1193
1194 return result;
1195 }