1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
7 #include "authutilities.h"
8 #include <Security/AuthorizationTags.h>
9 #include <dispatch/private.h>
10 #include <CommonCrypto/CommonCrypto.h>
14 typedef struct _auth_item_s
* auth_item_t
;
15 void auth_items_crypt_worker(auth_items_t items
, CFDataRef encryption_key
, bool(*function
)(auth_item_t
, CFDataRef
));
18 #pragma mark auth_item_t
21 __AUTH_BASE_STRUCT_HEADER__
;
23 AuthorizationItem data
;
29 auth_item_get_string(auth_item_t item
)
31 if (item
->bufLen
<= item
->data
.valueLength
) {
32 item
->bufLen
= item
->data
.valueLength
+1; // make sure buffer has a null char
33 item
->data
.value
= realloc(item
->data
.value
, item
->bufLen
);
34 if (item
->data
.value
== NULL
) {
35 // this is added to prevent running off into random memory if a string buffer doesn't have a null char
36 os_log_error(AUTHD_LOG
, "items: realloc failed");
39 ((uint8_t*)item
->data
.value
)[item
->bufLen
-1] = '\0';
41 return item
->data
.value
;
45 auth_item_copy_auth_item_xpc(auth_item_t item
)
47 xpc_object_t xpc_data
= xpc_dictionary_create(NULL
, NULL
, 0);
48 xpc_dictionary_set_string(xpc_data
, AUTH_XPC_ITEM_NAME
, item
->data
.name
);
49 if (item
->data
.value
) {
50 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
51 bool sensitive
= strcmp(item
->data
.name
, "password") == 0;
53 vm_address_t vmBytes
= 0;
54 size_t xpcOutOfBandBlockSize
= (item
->data
.valueLength
> 32768 ? item
->data
.valueLength
: 32768); // min 16K on 64-bit systems and 12K on 32-bit systems
55 vm_allocate(mach_task_self(), &vmBytes
, xpcOutOfBandBlockSize
, VM_FLAGS_ANYWHERE
);
56 memcpy((void *)vmBytes
, item
->data
.value
, item
->data
.valueLength
);
57 dispatch_data_t dispData
= dispatch_data_create((void *)vmBytes
, xpcOutOfBandBlockSize
, DISPATCH_TARGET_QUEUE_DEFAULT
, DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE
); // out-of-band mapping
58 xpc_object_t xpcData
= xpc_data_create_with_dispatch_data(dispData
);
59 dispatch_release(dispData
);
60 xpc_dictionary_set_value(xpc_data
, AUTH_XPC_ITEM_VALUE
, xpcData
);
62 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
, item
->data
.valueLength
);
64 xpc_dictionary_set_data(xpc_data
, AUTH_XPC_ITEM_VALUE
, item
->data
.value
, item
->data
.valueLength
);
67 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_FLAGS
, item
->data
.flags
);
68 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_TYPE
, item
->type
);
73 _auth_item_finalize(CFTypeRef value
)
75 auth_item_t item
= (auth_item_t
)value
;
77 if (item
->data
.name
) {
78 free((void*)item
->data
.name
);
79 /* cannot set item->data.name to NULL because item->data.name is non-nullable public API (rdar://problem/32235322)
80 * cannot leave item->data.name pointing to original data (rdar://problem/31006596)
81 * => suppress the warning */
82 #ifndef __clang_analyzer__
83 item
->data
.name
= NULL
;
87 if (item
->data
.value
) {
88 memset(item
->data
.value
, 0, item
->data
.valueLength
);
89 free_safe(item
->data
.value
);
94 _auth_item_equal(CFTypeRef value1
, CFTypeRef value2
)
96 return (CFHash(value1
) == CFHash(value2
));
100 _auth_item_copy_description(CFTypeRef value
)
103 auth_item_t item
= (auth_item_t
)value
;
106 static size_t passLen
= strlen(kAuthorizationEnvironmentPassword
);
107 if (strncasecmp(item
->data
.name
, kAuthorizationEnvironmentPassword
, passLen
) == 0) {
112 CFMutableStringRef desc
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
113 CFStringAppendFormat(desc
, NULL
, CFSTR("auth_item: %s, type=%i, length=%li, flags=%x"),
114 item
->data
.name
, item
->type
,
115 hidden
? 0 : item
->data
.valueLength
, (unsigned int)item
->data
.flags
);
117 switch (item
->type
) {
119 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%s"), hidden
? "(hidden)" : auth_item_get_string(item
));
122 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(int32_t*)item
->data
.value
);
125 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%u"), *(uint32_t*)item
->data
.value
);
128 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%lli"), *(int64_t*)item
->data
.value
);
131 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%llu"), *(uint64_t*)item
->data
.value
);
134 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(bool*)item
->data
.value
);
137 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%f"), *(double*)item
->data
.value
);
140 case AI_TYPE_UNKNOWN
:
142 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=(hidden)"));
144 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=0x"));
145 size_t i
= item
->data
.valueLength
< 10 ? item
->data
.valueLength
: 10;
146 uint8_t * data
= item
->data
.value
;
148 CFStringAppendFormat(desc
, NULL
, CFSTR("%02x"), data
[i
-1]);
159 _auth_item_hash(CFTypeRef value
)
161 auth_item_t item
= (auth_item_t
)value
;
162 uint64_t crc
= crc64_init();
163 crc
= crc64_update(crc
, item
->data
.name
, strlen(item
->data
.name
));
164 if (item
->data
.value
) {
165 crc
= crc64_update(crc
, item
->data
.value
, item
->data
.valueLength
);
167 crc
= crc64_update(crc
, &item
->data
.flags
, sizeof(item
->data
.flags
));
169 crc
= crc64_final(crc
);
170 return (CFHashCode
)crc
;
173 AUTH_TYPE_INSTANCE(auth_item
,
176 .finalize
= _auth_item_finalize
,
177 .equal
= _auth_item_equal
,
178 .hash
= _auth_item_hash
,
179 .copyFormattingDesc
= NULL
,
180 .copyDebugDesc
= _auth_item_copy_description
183 static CFTypeID
auth_item_get_type_id() {
184 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
185 static dispatch_once_t onceToken
;
187 dispatch_once(&onceToken
, ^{
188 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_item
);
197 auth_item_t item
= NULL
;
199 item
= (auth_item_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_item_get_type_id(), AUTH_CLASS_SIZE(auth_item
), NULL
);
200 require(item
!= NULL
, done
);
207 auth_item_create(uint32_t type
, const char * name
, const void * value
, size_t valueLen
, uint32_t flags
)
209 auth_item_t item
= NULL
;
210 require(name
!= NULL
, done
);
212 item
= _auth_item_create();
213 require(item
!= NULL
, done
);
216 item
->data
.flags
= flags
;
217 item
->data
.name
= _copy_string(name
);
218 item
->data
.valueLength
= valueLen
;
219 item
->bufLen
= valueLen
;
221 if (item
->type
== AI_TYPE_STRING
) {
223 item
->data
.value
= calloc(1u, item
->bufLen
);
224 } else if (valueLen
) {
225 item
->data
.value
= calloc(1u, item
->bufLen
);
228 memcpy(item
->data
.value
, value
, valueLen
);
237 auth_item_create_with_xpc(xpc_object_t data
)
239 auth_item_t item
= NULL
;
240 require(data
!= NULL
, done
);
241 require(xpc_get_type(data
) == XPC_TYPE_DICTIONARY
, done
);
242 require(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
) != NULL
, done
);
244 item
= _auth_item_create();
245 require(item
!= NULL
, done
);
247 item
->data
.name
= _copy_string(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
));
248 item
->data
.flags
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_FLAGS
);
249 item
->type
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_TYPE
);
252 const void * value
= xpc_dictionary_get_data(data
, AUTH_XPC_ITEM_VALUE
, &len
);
254 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
255 bool sensitive
= xpc_dictionary_get_value(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
257 size_t sensitiveLength
= (size_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
258 if (sensitiveLength
> len
) {
259 os_log_error(AUTHD_LOG
, "Sensitive data len %zu is not valid", sensitiveLength
);
262 item
->bufLen
= sensitiveLength
;
263 item
->data
.valueLength
= sensitiveLength
;
264 item
->data
.value
= calloc(1u, sensitiveLength
);
265 memcpy(item
->data
.value
, value
, sensitiveLength
);
266 memset_s((void *)value
, len
, 0, sensitiveLength
); // clear the sensitive data, memset_s is never optimized away
269 item
->data
.valueLength
= len
;
270 item
->data
.value
= calloc(1u, len
);
271 memcpy(item
->data
.value
, value
, len
);
279 static bool auth_item_crypt_worker(auth_item_t item
, CFDataRef key
, int operation
)
286 if (item
->data
.value
&& item
->data
.valueLength
) {
287 size_t required_length
= 0;
288 CCCryptorStatus status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
289 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
290 item
->data
.value
, item
->data
.valueLength
, NULL
, 0, &required_length
);
291 require(status
== kCCBufferTooSmall
, done
);
293 void *buffer
= calloc(1u, required_length
);
294 status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
295 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
296 item
->data
.value
, item
->data
.valueLength
, buffer
, required_length
, &required_length
);
297 if (status
== kCCSuccess
) {
298 memset(item
->data
.value
, 0, item
->data
.valueLength
);
299 free(item
->data
.value
);
300 item
->data
.value
= buffer
;
301 item
->data
.valueLength
= required_length
;
312 static bool auth_item_decrypt(auth_item_t item
, CFDataRef key
)
314 return auth_item_crypt_worker(item
, key
, kCCDecrypt
);
317 static bool auth_item_encrypt(auth_item_t item
, CFDataRef key
)
319 return auth_item_crypt_worker(item
, key
, kCCEncrypt
);
323 #pragma mark auth_items_t
325 struct _auth_items_s
{
326 __AUTH_BASE_STRUCT_HEADER__
;
328 CFMutableDictionaryRef dictionary
;
329 AuthorizationItemSet set
;
333 _auth_items_finalize(CFTypeRef value
)
335 auth_items_t items
= (auth_items_t
)value
;
337 CFReleaseNull(items
->dictionary
);
338 free_safe(items
->set
.items
)
342 _auth_items_equal(CFTypeRef value1
, CFTypeRef value2
)
344 auth_items_t items1
= (auth_items_t
)value1
;
345 auth_items_t items2
= (auth_items_t
)value2
;
347 return CFEqual(items1
->dictionary
, items2
->dictionary
);
351 auth_items_add_item(auth_items_t items
, auth_item_t item
)
353 CFStringRef cfName
= CFStringCreateWithCString(kCFAllocatorDefault
, item
->data
.name
, kCFStringEncodingUTF8
);
355 CFDictionarySetValue(items
->dictionary
, cfName
, item
);
361 _auth_items_copy_description(CFTypeRef value
)
363 auth_items_t items
= (auth_items_t
)value
;
364 return CFCopyDescription(items
->dictionary
);
367 AUTH_TYPE_INSTANCE(auth_items
,
370 .finalize
= _auth_items_finalize
,
371 .equal
= _auth_items_equal
,
373 .copyFormattingDesc
= NULL
,
374 .copyDebugDesc
= _auth_items_copy_description
377 CFTypeID
auth_items_get_type_id()
379 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
380 static dispatch_once_t onceToken
;
382 dispatch_once(&onceToken
, ^{
383 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_items
);
390 _auth_items_create(bool createDict
)
392 auth_items_t items
= NULL
;
394 items
= (auth_items_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_items_get_type_id(), AUTH_CLASS_SIZE(auth_items
), NULL
);
395 require(items
!= NULL
, done
);
398 items
->dictionary
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
408 auth_items_t items
= NULL
;
410 items
= _auth_items_create(true);
411 require(items
!= NULL
, done
);
418 _auth_items_parse_xpc(auth_items_t items
, const xpc_object_t data
)
421 require(data
!= NULL
, done
);
422 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
424 result
= xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
426 auth_item_t item
= auth_item_create_with_xpc(value
);
428 auth_items_add_item(items
, item
);
439 auth_items_t
auth_items_create_with_xpc(const xpc_object_t data
)
441 auth_items_t items
= NULL
;
443 items
= _auth_items_create(true);
444 require(items
!= NULL
, done
);
446 _auth_items_parse_xpc(items
, data
);
453 auth_items_create_copy(auth_items_t copy
)
455 auth_items_t items
= NULL
;
457 items
= _auth_items_create(false);
458 require(items
!= NULL
, done
);
460 items
->dictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(copy
->dictionary
), copy
->dictionary
);
467 auth_items_get_count(auth_items_t items
)
469 return (size_t)CFDictionaryGetCount(items
->dictionary
);
473 auth_items_export_xpc(auth_items_t items
)
475 xpc_object_t array
= xpc_array_create(NULL
, 0);
477 _cf_dictionary_iterate(items
->dictionary
, ^bool(CFTypeRef key AUTH_UNUSED
, CFTypeRef value
) {
478 auth_item_t item
= (auth_item_t
)value
;
479 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
480 xpc_array_append_value(array
, xpc_data
);
481 xpc_release_safe(xpc_data
);
489 _find_item(auth_items_t items
, const char * key
)
491 auth_item_t item
= NULL
;
492 CFStringRef lookup
= NULL
;
493 require(key
!= NULL
, done
);
495 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
496 require(lookup
!= NULL
, done
);
498 item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
501 CFReleaseSafe(lookup
);
506 auth_items_set_flags(auth_items_t items
, const char *key
, uint32_t flags
)
508 auth_item_t item
= _find_item(items
,key
);
510 item
->data
.flags
|= flags
;
515 auth_items_clear_flags(auth_items_t items
, const char *key
, uint32_t flags
)
517 auth_item_t item
= _find_item(items
,key
);
519 item
->data
.flags
&= ~flags
;
524 auth_items_get_flags(auth_items_t items
, const char *key
)
526 auth_item_t item
= _find_item(items
,key
);
528 return item
->data
.flags
;
535 auth_items_check_flags(auth_items_t items
, const char *key
, uint32_t flags
)
537 // When several bits are set in uint32_t flags, "(current & flags) != 0" checks if ANY flag is set, not all flags!
538 // This odd behavior is currently being relied upon in several places, so be careful when changing / fixing this.
539 // However, this also risks unwanted information leakage in
540 // AuthorizationCopyInfo ==> authorization_copy_info ==> [all info] auth_items_copy_with_flags
541 uint32_t current
= auth_items_get_flags(items
,key
);
542 return flags
? (current
& flags
) != 0 : current
== 0;
546 auth_items_set_key(auth_items_t items
, const char *key
)
548 auth_item_t item
= _find_item(items
,key
);
550 item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
552 auth_items_add_item(items
, item
);
559 auth_items_exist(auth_items_t items
, const char *key
)
561 return _find_item(items
,key
) != NULL
;
565 auth_items_remove(auth_items_t items
, const char *key
)
567 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
568 CFDictionaryRemoveValue(items
->dictionary
, lookup
);
569 CFReleaseSafe(lookup
);
573 auth_items_remove_with_flags(auth_items_t items
, uint32_t flags
)
575 auth_items_iterate(items
, ^bool(const char *key
) {
576 if (auth_items_check_flags(items
, key
, flags
)) {
577 auth_items_remove(items
,key
);
584 auth_items_clear(auth_items_t items
)
586 CFDictionaryRemoveAllValues(items
->dictionary
);
590 auth_items_crypt_worker(auth_items_t items
, CFDataRef encryption_key
, bool(*function
)(auth_item_t
, CFDataRef
))
592 auth_items_iterate(items
, ^bool(const char *key
) {
593 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
594 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
595 function(item
, encryption_key
);
596 CFReleaseSafe(lookup
);
602 auth_items_encrypt(auth_items_t items
, CFDataRef encryption_key
)
604 auth_items_crypt_worker(items
, encryption_key
, auth_item_encrypt
);
608 auth_items_decrypt(auth_items_t items
, CFDataRef encryption_key
)
610 auth_items_crypt_worker(items
, encryption_key
, auth_item_decrypt
);
614 auth_items_copy(auth_items_t items
, auth_items_t src
)
616 auth_items_iterate(src
, ^bool(const char *key
) {
620 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
621 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
622 if (item
) auth_items_add_item(items
, item
);
623 CFReleaseSafe(lookup
);
629 auth_items_content_copy(auth_items_t items
, auth_items_t src
)
631 auth_items_iterate(src
, ^bool(const char *key
) {
632 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
633 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
634 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
635 if (new_item
) auth_items_add_item(items
, new_item
);
636 CFReleaseSafe(lookup
);
637 CFReleaseSafe(new_item
);
643 auth_items_copy_xpc(auth_items_t items
, const xpc_object_t src
)
645 _auth_items_parse_xpc(items
,src
);
649 auth_items_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
651 auth_items_iterate(src
, ^bool(const char *key
) {
652 if (auth_items_check_flags(src
, key
, flags
)) {
653 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
654 if (CFDictionaryContainsKey(items
->dictionary
, lookup
)) {
655 CFDictionaryRemoveValue(items
->dictionary
, lookup
); // we do not want to have preserved unretained key
657 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
658 if (item
) auth_items_add_item(items
, item
);
659 CFReleaseSafe(lookup
);
665 // unlike previous method, this one creates true new copy including their content
667 auth_items_content_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
669 auth_items_iterate(src
, ^bool(const char *key
) {
670 if (auth_items_check_flags(src
, key
, flags
)) {
671 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
672 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
673 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
675 auth_items_add_item(items
, new_item
);
678 CFReleaseSafe(lookup
);
685 auth_items_iterate(auth_items_t items
, auth_items_iterator_t iter
)
688 CFTypeRef
* keys
= NULL
;
689 CFTypeRef
* values
= NULL
;
691 CFIndex count
= CFDictionaryGetCount(items
->dictionary
);
692 keys
= calloc((size_t)count
, sizeof(CFTypeRef
));
693 require(keys
!= NULL
, done
);
695 values
= calloc((size_t)count
, sizeof(CFTypeRef
));
696 require(values
!= NULL
, done
);
698 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
699 for (CFIndex i
= 0; i
< count
; i
++) {
700 auth_item_t item
= (auth_item_t
)values
[i
];
701 result
= iter(item
->data
.name
);
714 auth_items_set_string(auth_items_t items
, const char *key
, const char *value
)
716 assert(value
); // marked non-null
718 size_t valLen
= strlen(value
);
719 auth_item_t item
= _find_item(items
,key
);
720 if (item
&& item
->type
== AI_TYPE_STRING
&& valLen
< item
->bufLen
) {
721 memcpy(item
->data
.value
, value
, valLen
+1); // copy null
722 item
->data
.valueLength
= valLen
;
724 item
= auth_item_create(AI_TYPE_STRING
, key
, value
, valLen
, 0);
726 auth_items_add_item(items
, item
);
733 auth_items_get_string(auth_items_t items
, const char *key
)
735 auth_item_t item
= _find_item(items
,key
);
738 if (!(item
->type
== AI_TYPE_STRING
|| item
->type
== AI_TYPE_UNKNOWN
)) {
739 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
740 item
->data
.name
, item
->type
, AI_TYPE_STRING
);
743 return auth_item_get_string(item
);
750 auth_items_set_data(auth_items_t items
, const char *key
, const void *value
, size_t len
)
752 assert(value
); // marked non-null
755 auth_item_t item
= _find_item(items
,key
);
756 if (item
&& item
->type
== AI_TYPE_DATA
&& len
<= item
->bufLen
) {
757 memcpy(item
->data
.value
, value
, len
);
758 item
->data
.valueLength
= len
;
760 item
= auth_item_create(AI_TYPE_DATA
, key
, value
, len
, 0);
762 auth_items_add_item(items
, item
);
770 auth_items_get_data(auth_items_t items
, const char *key
, size_t *len
)
772 assert(len
); // marked non-null
774 auth_item_t item
= _find_item(items
,key
);
777 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
778 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
779 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
782 *len
= item
->data
.valueLength
;
783 return item
->data
.value
;
790 auth_items_get_data_with_flags(auth_items_t items
, const char *key
, size_t *len
, uint32_t flags
)
792 assert(len
); // marked non-null
794 auth_item_t item
= _find_item(items
,key
);
795 if (item
&& (item
->data
.flags
& flags
) == flags
) {
797 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
798 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
799 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
802 *len
= item
->data
.valueLength
;
804 return item
->data
.value
;
811 auth_items_set_bool(auth_items_t items
, const char *key
, bool value
)
813 auth_item_t item
= _find_item(items
,key
);
814 if (item
&& item
->type
== AI_TYPE_BOOL
) {
815 *(bool*)item
->data
.value
= value
;
817 item
= auth_item_create(AI_TYPE_BOOL
, key
, &value
, sizeof(bool), 0);
819 auth_items_add_item(items
, item
);
826 auth_items_get_bool(auth_items_t items
, const char *key
)
828 auth_item_t item
= _find_item(items
,key
);
831 if (!(item
->type
== AI_TYPE_BOOL
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(bool))) {
832 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
833 item
->data
.name
, item
->type
, AI_TYPE_BOOL
, item
->data
.valueLength
, sizeof(bool));
836 if (item
->type
== AI_TYPE_STRING
) {
837 return atoi(auth_item_get_string(item
));
840 require(item
->data
.value
!= NULL
, done
);
841 require(item
->data
.valueLength
== sizeof(bool), done
);
843 return *(bool*)item
->data
.value
;
851 auth_items_set_int(auth_items_t items
, const char *key
, int32_t value
)
853 auth_item_t item
= _find_item(items
,key
);
854 if (item
&& item
->type
== AI_TYPE_INT
) {
855 *(int32_t*)item
->data
.value
= value
;
857 item
= auth_item_create(AI_TYPE_INT
, key
, &value
, sizeof(int32_t), 0);
859 auth_items_add_item(items
, item
);
866 auth_items_get_int(auth_items_t items
, const char *key
)
868 auth_item_t item
= _find_item(items
,key
);
871 if (!(item
->type
==AI_TYPE_INT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int32_t))) {
872 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
873 item
->data
.name
, item
->type
, AI_TYPE_INT
, item
->data
.valueLength
, sizeof(int32_t));
876 if (item
->type
== AI_TYPE_STRING
) {
877 return atoi(auth_item_get_string(item
));
880 require(item
->data
.value
!= NULL
, done
);
881 require(item
->data
.valueLength
== sizeof(int32_t), done
);
883 return *(int32_t*)item
->data
.value
;
891 auth_items_set_uint(auth_items_t items
, const char *key
, uint32_t value
)
893 auth_item_t item
= _find_item(items
,key
);
894 if (item
&& item
->type
== AI_TYPE_UINT
) {
895 *(uint32_t*)item
->data
.value
= value
;
897 item
= auth_item_create(AI_TYPE_UINT
, key
, &value
, sizeof(uint32_t), 0);
899 auth_items_add_item(items
, item
);
906 auth_items_get_uint(auth_items_t items
, const char *key
)
908 auth_item_t item
= _find_item(items
,key
);
911 if (!(item
->type
==AI_TYPE_UINT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint32_t))) {
912 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
913 item
->data
.name
, item
->type
, AI_TYPE_UINT
, item
->data
.valueLength
, sizeof(uint32_t));
916 if (item
->type
== AI_TYPE_STRING
) {
917 return (uint32_t)atoi(auth_item_get_string(item
));
920 require(item
->data
.value
!= NULL
, done
);
921 require(item
->data
.valueLength
== sizeof(uint32_t), done
);
923 return *(uint32_t*)item
->data
.value
;
931 auth_items_set_int64(auth_items_t items
, const char *key
, int64_t value
)
933 auth_item_t item
= _find_item(items
,key
);
934 if (item
&& item
->type
== AI_TYPE_INT64
) {
935 *(int64_t*)item
->data
.value
= value
;
937 item
= auth_item_create(AI_TYPE_INT64
, key
, &value
, sizeof(int64_t), 0);
939 auth_items_add_item(items
, item
);
946 auth_items_get_int64(auth_items_t items
, const char *key
)
948 auth_item_t item
= _find_item(items
,key
);
951 if (!(item
->type
==AI_TYPE_INT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int64_t))) {
952 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
953 item
->data
.name
, item
->type
, AI_TYPE_INT64
, item
->data
.valueLength
, sizeof(int64_t));
956 if (item
->type
== AI_TYPE_STRING
) {
957 return atoll(auth_item_get_string(item
));
960 require(item
->data
.value
!= NULL
, done
);
961 require(item
->data
.valueLength
== sizeof(int64_t), done
);
963 return *(int64_t*)item
->data
.value
;
971 auth_items_set_uint64(auth_items_t items
, const char *key
, uint64_t value
)
973 auth_item_t item
= _find_item(items
,key
);
974 if (item
&& item
->type
== AI_TYPE_UINT64
) {
975 *(uint64_t*)item
->data
.value
= value
;
977 item
= auth_item_create(AI_TYPE_UINT64
, key
, &value
, sizeof(uint64_t), 0);
979 auth_items_add_item(items
, item
);
986 auth_items_get_uint64(auth_items_t items
, const char *key
)
988 auth_item_t item
= _find_item(items
,key
);
991 if (!(item
->type
==AI_TYPE_UINT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint64_t))) {
992 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
993 item
->data
.name
, item
->type
, AI_TYPE_UINT64
, item
->data
.valueLength
, sizeof(uint64_t));
996 if (item
->type
== AI_TYPE_STRING
) {
997 return (uint64_t)atoll(auth_item_get_string(item
));
1000 require(item
->data
.value
!= NULL
, done
);
1001 require(item
->data
.valueLength
== sizeof(uint64_t), done
);
1003 return *(uint64_t*)item
->data
.value
;
1010 void auth_items_set_double(auth_items_t items
, const char *key
, double value
)
1012 auth_item_t item
= _find_item(items
,key
);
1013 if (item
&& item
->type
== AI_TYPE_DOUBLE
) {
1014 *(double*)item
->data
.value
= value
;
1016 item
= auth_item_create(AI_TYPE_DOUBLE
, key
, &value
, sizeof(double), 0);
1018 auth_items_add_item(items
, item
);
1024 double auth_items_get_double(auth_items_t items
, const char *key
)
1026 auth_item_t item
= _find_item(items
,key
);
1029 if (!(item
->type
==AI_TYPE_DOUBLE
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(double))) {
1030 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
1031 item
->data
.name
, item
->type
, AI_TYPE_DOUBLE
, item
->data
.valueLength
, sizeof(double));
1034 if (item
->type
== AI_TYPE_STRING
) {
1035 return atof(auth_item_get_string(item
));
1038 require(item
->data
.value
!= NULL
, done
);
1039 require(item
->data
.valueLength
== sizeof(double), done
);
1041 return *(double*)item
->data
.value
;
1048 uint32_t auth_items_get_type(auth_items_t items
, const char *key
)
1050 auth_item_t item
= _find_item(items
,key
);
1055 return AI_TYPE_UNKNOWN
;
1058 size_t auth_items_get_length(auth_items_t items
, const char *key
)
1060 auth_item_t item
= _find_item(items
,key
);
1062 return item
->data
.valueLength
;
1068 void auth_items_set_value(auth_items_t items
, const char *key
, uint32_t type
, uint32_t flags
, const void *value
, size_t len
)
1070 auth_item_t item
= auth_item_create(type
, key
, value
, len
, flags
);
1072 auth_items_add_item(items
, item
);
1078 #pragma mark auth_rights_t
1080 struct _auth_rights_s
{
1081 __AUTH_BASE_STRUCT_HEADER__
;
1083 CFMutableArrayRef array
;
1087 _auth_rights_finalize(CFTypeRef value
)
1089 auth_rights_t rights
= (auth_rights_t
)value
;
1091 CFReleaseNull(rights
->array
);
1095 _auth_rights_equal(CFTypeRef value1
, CFTypeRef value2
)
1097 auth_rights_t rights1
= (auth_rights_t
)value1
;
1098 auth_rights_t rights2
= (auth_rights_t
)value2
;
1100 return CFEqual(rights1
->array
, rights2
->array
);
1104 _auth_rights_copy_description(CFTypeRef value
)
1106 auth_rights_t rights
= (auth_rights_t
)value
;
1107 return CFCopyDescription(rights
->array
);
1110 AUTH_TYPE_INSTANCE(auth_rights
,
1113 .finalize
= _auth_rights_finalize
,
1114 .equal
= _auth_rights_equal
,
1116 .copyFormattingDesc
= NULL
,
1117 .copyDebugDesc
= _auth_rights_copy_description
1120 static CFTypeID
auth_rights_get_type_id()
1122 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
1123 static dispatch_once_t onceToken
;
1125 dispatch_once(&onceToken
, ^{
1126 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_rights
);
1132 static auth_rights_t
1133 _auth_rights_create()
1135 auth_rights_t rights
= NULL
;
1137 rights
= (auth_rights_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights
), NULL
);
1138 require(rights
!= NULL
, done
);
1140 rights
->array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1147 auth_rights_create()
1149 auth_rights_t rights
= _auth_rights_create();
1150 require(rights
!= NULL
, done
);
1156 auth_rights_t
auth_rights_create_with_xpc(const xpc_object_t data
)
1158 auth_rights_t rights
= _auth_rights_create();
1159 require(rights
!= NULL
, done
);
1160 require(data
!= NULL
, done
);
1161 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
1163 xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
1165 auth_item_t item
= auth_item_create_with_xpc(value
);
1167 CFArrayAppendValue(rights
->array
, item
);
1168 CFReleaseSafe(item
);
1178 xpc_object_t
auth_rights_export_xpc(auth_rights_t rights
)
1180 xpc_object_t array
= xpc_array_create(NULL
, 0);
1182 CFIndex count
= CFArrayGetCount(rights
->array
);
1183 for (CFIndex i
= 0; i
< count
; i
++) {
1184 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1185 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
1186 xpc_array_append_value(array
, xpc_data
);
1187 xpc_release_safe(xpc_data
);
1194 _find_right_item(auth_rights_t rights
, const char * key
)
1196 auth_item_t item
= NULL
;
1197 require(key
!= NULL
, done
);
1199 CFIndex count
= CFArrayGetCount(rights
->array
);
1200 for (CFIndex i
= 0; i
< count
; i
++) {
1201 auth_item_t tmp
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1202 if (tmp
&& strcmp(tmp
->data
.name
, key
) == 0) {
1212 void auth_rights_set_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1214 auth_item_t item
= _find_right_item(rights
,key
);
1216 item
->data
.flags
|= flags
;
1220 void auth_rights_clear_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1222 auth_item_t item
= _find_right_item(rights
,key
);
1224 item
->data
.flags
&= ~flags
;
1228 uint32_t auth_rights_get_flags(auth_rights_t rights
, const char *key
)
1230 auth_item_t item
= _find_right_item(rights
,key
);
1232 return item
->data
.flags
;
1238 bool auth_rights_check_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1240 uint32_t current
= auth_rights_get_flags(rights
,key
);
1241 return flags
? (current
& flags
) != 0 : current
== 0;
1244 size_t auth_rights_get_count(auth_rights_t rights
)
1246 return (size_t)CFArrayGetCount(rights
->array
);
1249 void auth_rights_add(auth_rights_t rights
, const char *key
)
1251 auth_item_t item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
1253 CFArrayAppendValue(rights
->array
, item
);
1254 CFReleaseSafe(item
);
1258 bool auth_rights_exist(auth_rights_t rights
, const char *key
)
1260 return (_find_right_item(rights
,key
) != NULL
);
1263 void auth_rights_remove(auth_rights_t rights
, const char *key
)
1265 CFIndex count
= CFArrayGetCount(rights
->array
);
1266 for (CFIndex i
= 0; i
< count
; i
++) {
1267 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1268 if (item
&& strcmp(item
->data
.name
, key
) == 0) {
1269 CFArrayRemoveValueAtIndex(rights
->array
, i
);
1276 void auth_rights_clear(auth_rights_t rights
)
1278 CFArrayRemoveAllValues(rights
->array
);
1282 auth_rights_iterate(auth_rights_t rights
, bool(^iter
)(const char * key
))
1284 bool result
= false;
1286 CFIndex count
= CFArrayGetCount(rights
->array
);
1287 for (CFIndex i
= 0; i
< count
; i
++) {
1288 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1289 result
= iter(item
->data
.name
);