1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
7 #include "authutilities.h"
8 #include <Security/AuthorizationTags.h>
9 #include <Security/AuthorizationTagsPriv.h>
10 #include <dispatch/private.h>
11 #include <CommonCrypto/CommonCrypto.h>
13 #include <security_utilities/simulatecrash_assert.h>
17 typedef struct _auth_item_s
* auth_item_t
;
18 void auth_items_crypt_worker(auth_items_t items
, CFDataRef encryption_key
, bool(*function
)(auth_item_t
, CFDataRef
));
21 #pragma mark auth_item_t
24 __AUTH_BASE_STRUCT_HEADER__
;
26 AuthorizationItem data
;
32 auth_item_get_string(auth_item_t item
)
34 if (item
->bufLen
<= item
->data
.valueLength
) {
35 item
->bufLen
= item
->data
.valueLength
+1; // make sure buffer has a null char
36 item
->data
.value
= realloc(item
->data
.value
, item
->bufLen
);
37 if (item
->data
.value
== NULL
) {
38 // this is added to prevent running off into random memory if a string buffer doesn't have a null char
39 os_log_error(AUTHD_LOG
, "items: realloc failed");
42 ((uint8_t*)item
->data
.value
)[item
->bufLen
-1] = '\0';
44 return item
->data
.value
;
48 auth_item_copy_auth_item_xpc(auth_item_t item
)
50 xpc_object_t xpc_data
= xpc_dictionary_create(NULL
, NULL
, 0);
51 xpc_dictionary_set_string(xpc_data
, AUTH_XPC_ITEM_NAME
, item
->data
.name
);
52 if (item
->data
.value
) {
53 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
54 bool sensitive
= strcmp(item
->data
.name
, AGENT_PASSWORD
) == 0;
56 vm_address_t vmBytes
= 0;
57 size_t xpcOutOfBandBlockSize
= (item
->data
.valueLength
> 32768 ? item
->data
.valueLength
: 32768); // min 16K on 64-bit systems and 12K on 32-bit systems
58 vm_allocate(mach_task_self(), &vmBytes
, xpcOutOfBandBlockSize
, VM_FLAGS_ANYWHERE
);
59 memcpy((void *)vmBytes
, item
->data
.value
, item
->data
.valueLength
);
60 dispatch_data_t dispData
= dispatch_data_create((void *)vmBytes
, xpcOutOfBandBlockSize
, DISPATCH_TARGET_QUEUE_DEFAULT
, DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE
); // out-of-band mapping
61 xpc_object_t xpcData
= xpc_data_create_with_dispatch_data(dispData
);
62 dispatch_release(dispData
);
63 xpc_dictionary_set_value(xpc_data
, AUTH_XPC_ITEM_VALUE
, xpcData
);
65 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
, item
->data
.valueLength
);
67 xpc_dictionary_set_data(xpc_data
, AUTH_XPC_ITEM_VALUE
, item
->data
.value
, item
->data
.valueLength
);
70 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_FLAGS
, item
->data
.flags
);
71 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_TYPE
, item
->type
);
76 _auth_item_finalize(CFTypeRef value
)
78 auth_item_t item
= (auth_item_t
)value
;
80 if (item
->data
.name
) {
81 free((void*)item
->data
.name
);
82 /* cannot set item->data.name to NULL because item->data.name is non-nullable public API (rdar://problem/32235322)
83 * cannot leave item->data.name pointing to original data (rdar://problem/31006596)
84 * => suppress the warning */
85 #ifndef __clang_analyzer__
86 item
->data
.name
= NULL
;
90 if (item
->data
.value
) {
91 memset(item
->data
.value
, 0, item
->data
.valueLength
);
92 free_safe(item
->data
.value
);
97 _auth_item_equal(CFTypeRef value1
, CFTypeRef value2
)
99 return (CFHash(value1
) == CFHash(value2
));
103 _auth_item_copy_description(CFTypeRef value
)
106 auth_item_t item
= (auth_item_t
)value
;
109 static size_t passLen
= strlen(kAuthorizationEnvironmentPassword
);
110 if (strncasecmp(item
->data
.name
, kAuthorizationEnvironmentPassword
, passLen
) == 0) {
115 CFMutableStringRef desc
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
116 CFStringAppendFormat(desc
, NULL
, CFSTR("auth_item: %s, type=%i, length=%li, flags=%x"),
117 item
->data
.name
, item
->type
,
118 hidden
? 0 : item
->data
.valueLength
, (unsigned int)item
->data
.flags
);
120 switch (item
->type
) {
122 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%s"), hidden
? "(hidden)" : auth_item_get_string(item
));
125 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(int32_t*)item
->data
.value
);
128 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%u"), *(uint32_t*)item
->data
.value
);
131 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%lli"), *(int64_t*)item
->data
.value
);
134 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%llu"), *(uint64_t*)item
->data
.value
);
137 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(bool*)item
->data
.value
);
140 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%f"), *(double*)item
->data
.value
);
143 case AI_TYPE_UNKNOWN
:
145 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=(hidden)"));
147 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=0x"));
148 size_t i
= item
->data
.valueLength
< 10 ? item
->data
.valueLength
: 10;
149 uint8_t * data
= item
->data
.value
;
151 CFStringAppendFormat(desc
, NULL
, CFSTR("%02x"), data
[i
-1]);
162 _auth_item_hash(CFTypeRef value
)
164 auth_item_t item
= (auth_item_t
)value
;
165 uint64_t crc
= crc64_init();
166 crc
= crc64_update(crc
, item
->data
.name
, strlen(item
->data
.name
));
167 if (item
->data
.value
) {
168 crc
= crc64_update(crc
, item
->data
.value
, item
->data
.valueLength
);
170 crc
= crc64_update(crc
, &item
->data
.flags
, sizeof(item
->data
.flags
));
172 crc
= crc64_final(crc
);
173 return (CFHashCode
)crc
;
176 AUTH_TYPE_INSTANCE(auth_item
,
179 .finalize
= _auth_item_finalize
,
180 .equal
= _auth_item_equal
,
181 .hash
= _auth_item_hash
,
182 .copyFormattingDesc
= NULL
,
183 .copyDebugDesc
= _auth_item_copy_description
186 static CFTypeID
auth_item_get_type_id() {
187 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
188 static dispatch_once_t onceToken
;
190 dispatch_once(&onceToken
, ^{
191 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_item
);
200 auth_item_t item
= NULL
;
202 item
= (auth_item_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_item_get_type_id(), AUTH_CLASS_SIZE(auth_item
), NULL
);
203 require(item
!= NULL
, done
);
210 auth_item_create(uint32_t type
, const char * name
, const void * value
, size_t valueLen
, uint32_t flags
)
212 auth_item_t item
= NULL
;
213 require(name
!= NULL
, done
);
215 item
= _auth_item_create();
216 require(item
!= NULL
, done
);
219 item
->data
.flags
= flags
;
220 item
->data
.name
= _copy_string(name
);
221 item
->data
.valueLength
= valueLen
;
222 item
->bufLen
= valueLen
;
224 if (item
->type
== AI_TYPE_STRING
) {
226 item
->data
.value
= calloc(1u, item
->bufLen
);
227 } else if (valueLen
) {
228 item
->data
.value
= calloc(1u, item
->bufLen
);
231 memcpy(item
->data
.value
, value
, valueLen
);
240 auth_item_create_with_xpc(xpc_object_t data
)
242 auth_item_t item
= NULL
;
243 require(data
!= NULL
, done
);
244 require(xpc_get_type(data
) == XPC_TYPE_DICTIONARY
, done
);
245 require(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
) != NULL
, done
);
247 item
= _auth_item_create();
248 require(item
!= NULL
, done
);
250 item
->data
.name
= _copy_string(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
));
251 item
->data
.flags
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_FLAGS
);
252 item
->type
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_TYPE
);
255 const void * value
= xpc_dictionary_get_data(data
, AUTH_XPC_ITEM_VALUE
, &len
);
257 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
258 bool sensitive
= xpc_dictionary_get_value(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
260 size_t sensitiveLength
= (size_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
261 if (sensitiveLength
> len
) {
262 os_log_error(AUTHD_LOG
, "Sensitive data len %zu is not valid", sensitiveLength
);
265 item
->bufLen
= sensitiveLength
;
266 item
->data
.valueLength
= sensitiveLength
;
267 item
->data
.value
= calloc(1u, sensitiveLength
);
268 memcpy(item
->data
.value
, value
, sensitiveLength
);
269 memset_s((void *)value
, len
, 0, sensitiveLength
); // clear the sensitive data, memset_s is never optimized away
272 item
->data
.valueLength
= len
;
273 item
->data
.value
= calloc(1u, len
);
274 memcpy(item
->data
.value
, value
, len
);
282 static bool auth_item_crypt_worker(auth_item_t item
, CFDataRef key
, int operation
)
289 if (item
->data
.value
&& item
->data
.valueLength
) {
290 size_t required_length
= 0;
291 CCCryptorStatus status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
292 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
293 item
->data
.value
, item
->data
.valueLength
, NULL
, 0, &required_length
);
294 require(status
== kCCBufferTooSmall
, done
);
296 void *buffer
= calloc(1u, required_length
);
297 status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
298 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
299 item
->data
.value
, item
->data
.valueLength
, buffer
, required_length
, &required_length
);
300 if (status
== kCCSuccess
) {
301 memset(item
->data
.value
, 0, item
->data
.valueLength
);
302 free(item
->data
.value
);
303 item
->data
.value
= buffer
;
304 item
->data
.valueLength
= required_length
;
315 static bool auth_item_decrypt(auth_item_t item
, CFDataRef key
)
317 return auth_item_crypt_worker(item
, key
, kCCDecrypt
);
320 static bool auth_item_encrypt(auth_item_t item
, CFDataRef key
)
322 return auth_item_crypt_worker(item
, key
, kCCEncrypt
);
326 #pragma mark auth_items_t
328 struct _auth_items_s
{
329 __AUTH_BASE_STRUCT_HEADER__
;
331 CFMutableDictionaryRef dictionary
;
332 AuthorizationItemSet set
;
336 _auth_items_finalize(CFTypeRef value
)
338 auth_items_t items
= (auth_items_t
)value
;
340 CFReleaseNull(items
->dictionary
);
341 free_safe(items
->set
.items
)
345 _auth_items_equal(CFTypeRef value1
, CFTypeRef value2
)
347 auth_items_t items1
= (auth_items_t
)value1
;
348 auth_items_t items2
= (auth_items_t
)value2
;
350 return CFEqual(items1
->dictionary
, items2
->dictionary
);
354 auth_items_add_item(auth_items_t items
, auth_item_t item
)
356 CFStringRef cfName
= CFStringCreateWithCString(kCFAllocatorDefault
, item
->data
.name
, kCFStringEncodingUTF8
);
358 CFDictionarySetValue(items
->dictionary
, cfName
, item
);
364 _auth_items_copy_description(CFTypeRef value
)
366 auth_items_t items
= (auth_items_t
)value
;
367 return CFCopyDescription(items
->dictionary
);
370 AUTH_TYPE_INSTANCE(auth_items
,
373 .finalize
= _auth_items_finalize
,
374 .equal
= _auth_items_equal
,
376 .copyFormattingDesc
= NULL
,
377 .copyDebugDesc
= _auth_items_copy_description
380 CFTypeID
auth_items_get_type_id()
382 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
383 static dispatch_once_t onceToken
;
385 dispatch_once(&onceToken
, ^{
386 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_items
);
393 _auth_items_create(bool createDict
)
395 auth_items_t items
= NULL
;
397 items
= (auth_items_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_items_get_type_id(), AUTH_CLASS_SIZE(auth_items
), NULL
);
398 require(items
!= NULL
, done
);
401 items
->dictionary
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
411 auth_items_t items
= NULL
;
413 items
= _auth_items_create(true);
414 require(items
!= NULL
, done
);
421 _auth_items_parse_xpc(auth_items_t items
, const xpc_object_t data
)
424 require(data
!= NULL
, done
);
425 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
427 result
= xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
429 auth_item_t item
= auth_item_create_with_xpc(value
);
431 auth_items_add_item(items
, item
);
442 auth_items_t
auth_items_create_with_xpc(const xpc_object_t data
)
444 auth_items_t items
= NULL
;
446 items
= _auth_items_create(true);
447 require(items
!= NULL
, done
);
449 _auth_items_parse_xpc(items
, data
);
456 auth_items_create_copy(auth_items_t copy
)
458 auth_items_t items
= NULL
;
460 items
= _auth_items_create(false);
461 require(items
!= NULL
, done
);
463 items
->dictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(copy
->dictionary
), copy
->dictionary
);
470 auth_items_get_count(auth_items_t items
)
472 return (size_t)CFDictionaryGetCount(items
->dictionary
);
476 auth_items_export_xpc(auth_items_t items
)
478 xpc_object_t array
= xpc_array_create(NULL
, 0);
480 _cf_dictionary_iterate(items
->dictionary
, ^bool(CFTypeRef key AUTH_UNUSED
, CFTypeRef value
) {
481 auth_item_t item
= (auth_item_t
)value
;
482 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
483 xpc_array_append_value(array
, xpc_data
);
484 xpc_release_safe(xpc_data
);
492 _find_item(auth_items_t items
, const char * key
)
494 auth_item_t item
= NULL
;
495 CFStringRef lookup
= NULL
;
496 require(key
!= NULL
, done
);
498 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
499 require(lookup
!= NULL
, done
);
501 item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
504 CFReleaseSafe(lookup
);
509 auth_items_set_flags(auth_items_t items
, const char *key
, uint32_t flags
)
511 auth_item_t item
= _find_item(items
,key
);
513 item
->data
.flags
|= flags
;
518 auth_items_clear_flags(auth_items_t items
, const char *key
, uint32_t flags
)
520 auth_item_t item
= _find_item(items
,key
);
522 item
->data
.flags
&= ~flags
;
527 auth_items_get_flags(auth_items_t items
, const char *key
)
529 auth_item_t item
= _find_item(items
,key
);
531 return item
->data
.flags
;
538 auth_items_check_flags(auth_items_t items
, const char *key
, uint32_t flags
)
540 // When several bits are set in uint32_t flags, "(current & flags) != 0" checks if ANY flag is set, not all flags!
541 // This odd behavior is currently being relied upon in several places, so be careful when changing / fixing this.
542 // However, this also risks unwanted information leakage in
543 // AuthorizationCopyInfo ==> authorization_copy_info ==> [all info] auth_items_copy_with_flags
544 uint32_t current
= auth_items_get_flags(items
,key
);
545 return flags
? (current
& flags
) != 0 : current
== 0;
549 auth_items_set_key(auth_items_t items
, const char *key
)
551 auth_item_t item
= _find_item(items
,key
);
553 item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
555 auth_items_add_item(items
, item
);
562 auth_items_exist(auth_items_t items
, const char *key
)
564 return _find_item(items
,key
) != NULL
;
568 auth_items_remove(auth_items_t items
, const char *key
)
570 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
571 CFDictionaryRemoveValue(items
->dictionary
, lookup
);
572 CFReleaseSafe(lookup
);
576 auth_items_remove_with_flags(auth_items_t items
, uint32_t flags
)
578 auth_items_iterate(items
, ^bool(const char *key
) {
579 if (auth_items_check_flags(items
, key
, flags
)) {
580 auth_items_remove(items
,key
);
587 auth_items_clear(auth_items_t items
)
589 CFDictionaryRemoveAllValues(items
->dictionary
);
593 auth_items_crypt_worker(auth_items_t items
, CFDataRef encryption_key
, bool(*function
)(auth_item_t
, CFDataRef
))
595 auth_items_iterate(items
, ^bool(const char *key
) {
596 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
597 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
598 function(item
, encryption_key
);
599 CFReleaseSafe(lookup
);
605 auth_items_encrypt(auth_items_t items
, CFDataRef encryption_key
)
607 auth_items_crypt_worker(items
, encryption_key
, auth_item_encrypt
);
611 auth_items_decrypt(auth_items_t items
, CFDataRef encryption_key
)
613 auth_items_crypt_worker(items
, encryption_key
, auth_item_decrypt
);
617 auth_items_copy(auth_items_t items
, auth_items_t src
)
619 auth_items_iterate(src
, ^bool(const char *key
) {
623 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
624 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
625 if (item
) auth_items_add_item(items
, item
);
626 CFReleaseSafe(lookup
);
632 auth_items_content_copy(auth_items_t items
, auth_items_t src
)
634 auth_items_iterate(src
, ^bool(const char *key
) {
635 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
636 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
637 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
638 if (new_item
) auth_items_add_item(items
, new_item
);
639 CFReleaseSafe(lookup
);
640 CFReleaseSafe(new_item
);
646 auth_items_copy_xpc(auth_items_t items
, const xpc_object_t src
)
648 _auth_items_parse_xpc(items
,src
);
652 auth_items_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
654 auth_items_iterate(src
, ^bool(const char *key
) {
655 if (auth_items_check_flags(src
, key
, flags
)) {
656 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
657 if (CFDictionaryContainsKey(items
->dictionary
, lookup
)) {
658 CFDictionaryRemoveValue(items
->dictionary
, lookup
); // we do not want to have preserved unretained key
660 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
661 if (item
) auth_items_add_item(items
, item
);
662 CFReleaseSafe(lookup
);
668 // unlike previous method, this one creates true new copy including their content
670 auth_items_content_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
672 auth_items_iterate(src
, ^bool(const char *key
) {
673 if (auth_items_check_flags(src
, key
, flags
)) {
674 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
675 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
676 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
678 auth_items_add_item(items
, new_item
);
681 CFReleaseSafe(lookup
);
688 auth_items_iterate(auth_items_t items
, auth_items_iterator_t iter
)
691 CFTypeRef
* keys
= NULL
;
692 CFTypeRef
* values
= NULL
;
694 CFIndex count
= CFDictionaryGetCount(items
->dictionary
);
695 keys
= calloc((size_t)count
, sizeof(CFTypeRef
));
696 require(keys
!= NULL
, done
);
698 values
= calloc((size_t)count
, sizeof(CFTypeRef
));
699 require(values
!= NULL
, done
);
701 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
702 for (CFIndex i
= 0; i
< count
; i
++) {
703 auth_item_t item
= (auth_item_t
)values
[i
];
704 result
= iter(item
->data
.name
);
717 auth_items_set_string(auth_items_t items
, const char *key
, const char *value
)
719 assert(value
); // marked non-null
721 size_t valLen
= strlen(value
);
722 auth_item_t item
= _find_item(items
,key
);
723 if (item
&& item
->type
== AI_TYPE_STRING
&& valLen
< item
->bufLen
) {
724 memcpy(item
->data
.value
, value
, valLen
+1); // copy null
725 item
->data
.valueLength
= valLen
;
727 item
= auth_item_create(AI_TYPE_STRING
, key
, value
, valLen
, 0);
729 auth_items_add_item(items
, item
);
736 auth_items_get_string(auth_items_t items
, const char *key
)
738 auth_item_t item
= _find_item(items
,key
);
741 if (!(item
->type
== AI_TYPE_STRING
|| item
->type
== AI_TYPE_UNKNOWN
)) {
742 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
743 item
->data
.name
, item
->type
, AI_TYPE_STRING
);
746 return auth_item_get_string(item
);
753 auth_items_set_data(auth_items_t items
, const char *key
, const void *value
, size_t len
)
755 assert(value
); // marked non-null
758 auth_item_t item
= _find_item(items
,key
);
759 if (item
&& item
->type
== AI_TYPE_DATA
&& len
<= item
->bufLen
) {
760 memcpy(item
->data
.value
, value
, len
);
761 item
->data
.valueLength
= len
;
763 item
= auth_item_create(AI_TYPE_DATA
, key
, value
, len
, 0);
765 auth_items_add_item(items
, item
);
773 auth_items_get_data(auth_items_t items
, const char *key
, size_t *len
)
775 assert(len
); // marked non-null
777 auth_item_t item
= _find_item(items
,key
);
780 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
781 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
782 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
785 *len
= item
->data
.valueLength
;
786 return item
->data
.value
;
793 auth_items_get_data_with_flags(auth_items_t items
, const char *key
, size_t *len
, uint32_t flags
)
795 assert(len
); // marked non-null
797 auth_item_t item
= _find_item(items
,key
);
798 if (item
&& (item
->data
.flags
& flags
) == flags
) {
800 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
801 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
802 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
805 *len
= item
->data
.valueLength
;
807 return item
->data
.value
;
814 auth_items_set_bool(auth_items_t items
, const char *key
, bool value
)
816 auth_item_t item
= _find_item(items
,key
);
817 if (item
&& item
->type
== AI_TYPE_BOOL
) {
818 *(bool*)item
->data
.value
= value
;
820 item
= auth_item_create(AI_TYPE_BOOL
, key
, &value
, sizeof(bool), 0);
822 auth_items_add_item(items
, item
);
829 auth_items_get_bool(auth_items_t items
, const char *key
)
831 auth_item_t item
= _find_item(items
,key
);
834 if (!(item
->type
== AI_TYPE_BOOL
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(bool))) {
835 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
836 item
->data
.name
, item
->type
, AI_TYPE_BOOL
, item
->data
.valueLength
, sizeof(bool));
839 if (item
->type
== AI_TYPE_STRING
) {
840 return atoi(auth_item_get_string(item
));
843 require(item
->data
.value
!= NULL
, done
);
844 require(item
->data
.valueLength
== sizeof(bool), done
);
846 return *(bool*)item
->data
.value
;
854 auth_items_set_int(auth_items_t items
, const char *key
, int32_t value
)
856 auth_item_t item
= _find_item(items
,key
);
857 if (item
&& item
->type
== AI_TYPE_INT
) {
858 *(int32_t*)item
->data
.value
= value
;
860 item
= auth_item_create(AI_TYPE_INT
, key
, &value
, sizeof(int32_t), 0);
862 auth_items_add_item(items
, item
);
869 auth_items_get_int(auth_items_t items
, const char *key
)
871 auth_item_t item
= _find_item(items
,key
);
874 if (!(item
->type
==AI_TYPE_INT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int32_t))) {
875 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
876 item
->data
.name
, item
->type
, AI_TYPE_INT
, item
->data
.valueLength
, sizeof(int32_t));
879 if (item
->type
== AI_TYPE_STRING
) {
880 return atoi(auth_item_get_string(item
));
883 require(item
->data
.value
!= NULL
, done
);
884 require(item
->data
.valueLength
== sizeof(int32_t), done
);
886 return *(int32_t*)item
->data
.value
;
894 auth_items_set_uint(auth_items_t items
, const char *key
, uint32_t value
)
896 auth_item_t item
= _find_item(items
,key
);
897 if (item
&& item
->type
== AI_TYPE_UINT
) {
898 *(uint32_t*)item
->data
.value
= value
;
900 item
= auth_item_create(AI_TYPE_UINT
, key
, &value
, sizeof(uint32_t), 0);
902 auth_items_add_item(items
, item
);
909 auth_items_get_uint(auth_items_t items
, const char *key
)
911 auth_item_t item
= _find_item(items
,key
);
914 if (!(item
->type
==AI_TYPE_UINT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint32_t))) {
915 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
916 item
->data
.name
, item
->type
, AI_TYPE_UINT
, item
->data
.valueLength
, sizeof(uint32_t));
919 if (item
->type
== AI_TYPE_STRING
) {
920 return (uint32_t)atoi(auth_item_get_string(item
));
923 require(item
->data
.value
!= NULL
, done
);
924 require(item
->data
.valueLength
== sizeof(uint32_t), done
);
926 return *(uint32_t*)item
->data
.value
;
934 auth_items_set_int64(auth_items_t items
, const char *key
, int64_t value
)
936 auth_item_t item
= _find_item(items
,key
);
937 if (item
&& item
->type
== AI_TYPE_INT64
) {
938 *(int64_t*)item
->data
.value
= value
;
940 item
= auth_item_create(AI_TYPE_INT64
, key
, &value
, sizeof(int64_t), 0);
942 auth_items_add_item(items
, item
);
949 auth_items_get_int64(auth_items_t items
, const char *key
)
951 auth_item_t item
= _find_item(items
,key
);
954 if (!(item
->type
==AI_TYPE_INT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int64_t))) {
955 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
956 item
->data
.name
, item
->type
, AI_TYPE_INT64
, item
->data
.valueLength
, sizeof(int64_t));
959 if (item
->type
== AI_TYPE_STRING
) {
960 return atoll(auth_item_get_string(item
));
963 require(item
->data
.value
!= NULL
, done
);
964 require(item
->data
.valueLength
== sizeof(int64_t), done
);
966 return *(int64_t*)item
->data
.value
;
974 auth_items_set_uint64(auth_items_t items
, const char *key
, uint64_t value
)
976 auth_item_t item
= _find_item(items
,key
);
977 if (item
&& item
->type
== AI_TYPE_UINT64
) {
978 *(uint64_t*)item
->data
.value
= value
;
980 item
= auth_item_create(AI_TYPE_UINT64
, key
, &value
, sizeof(uint64_t), 0);
982 auth_items_add_item(items
, item
);
989 auth_items_get_uint64(auth_items_t items
, const char *key
)
991 auth_item_t item
= _find_item(items
,key
);
994 if (!(item
->type
==AI_TYPE_UINT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint64_t))) {
995 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
996 item
->data
.name
, item
->type
, AI_TYPE_UINT64
, item
->data
.valueLength
, sizeof(uint64_t));
999 if (item
->type
== AI_TYPE_STRING
) {
1000 return (uint64_t)atoll(auth_item_get_string(item
));
1003 require(item
->data
.value
!= NULL
, done
);
1004 require(item
->data
.valueLength
== sizeof(uint64_t), done
);
1006 return *(uint64_t*)item
->data
.value
;
1013 void auth_items_set_double(auth_items_t items
, const char *key
, double value
)
1015 auth_item_t item
= _find_item(items
,key
);
1016 if (item
&& item
->type
== AI_TYPE_DOUBLE
) {
1017 *(double*)item
->data
.value
= value
;
1019 item
= auth_item_create(AI_TYPE_DOUBLE
, key
, &value
, sizeof(double), 0);
1021 auth_items_add_item(items
, item
);
1027 double auth_items_get_double(auth_items_t items
, const char *key
)
1029 auth_item_t item
= _find_item(items
,key
);
1032 if (!(item
->type
==AI_TYPE_DOUBLE
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(double))) {
1033 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
1034 item
->data
.name
, item
->type
, AI_TYPE_DOUBLE
, item
->data
.valueLength
, sizeof(double));
1037 if (item
->type
== AI_TYPE_STRING
) {
1038 return atof(auth_item_get_string(item
));
1041 require(item
->data
.value
!= NULL
, done
);
1042 require(item
->data
.valueLength
== sizeof(double), done
);
1044 return *(double*)item
->data
.value
;
1051 uint32_t auth_items_get_type(auth_items_t items
, const char *key
)
1053 auth_item_t item
= _find_item(items
,key
);
1058 return AI_TYPE_UNKNOWN
;
1061 size_t auth_items_get_length(auth_items_t items
, const char *key
)
1063 auth_item_t item
= _find_item(items
,key
);
1065 return item
->data
.valueLength
;
1071 void auth_items_set_value(auth_items_t items
, const char *key
, uint32_t type
, uint32_t flags
, const void *value
, size_t len
)
1073 auth_item_t item
= auth_item_create(type
, key
, value
, len
, flags
);
1075 auth_items_add_item(items
, item
);
1081 #pragma mark auth_rights_t
1083 struct _auth_rights_s
{
1084 __AUTH_BASE_STRUCT_HEADER__
;
1086 CFMutableArrayRef array
;
1090 _auth_rights_finalize(CFTypeRef value
)
1092 auth_rights_t rights
= (auth_rights_t
)value
;
1094 CFReleaseNull(rights
->array
);
1098 _auth_rights_equal(CFTypeRef value1
, CFTypeRef value2
)
1100 auth_rights_t rights1
= (auth_rights_t
)value1
;
1101 auth_rights_t rights2
= (auth_rights_t
)value2
;
1103 return CFEqual(rights1
->array
, rights2
->array
);
1107 _auth_rights_copy_description(CFTypeRef value
)
1109 auth_rights_t rights
= (auth_rights_t
)value
;
1110 return CFCopyDescription(rights
->array
);
1113 AUTH_TYPE_INSTANCE(auth_rights
,
1116 .finalize
= _auth_rights_finalize
,
1117 .equal
= _auth_rights_equal
,
1119 .copyFormattingDesc
= NULL
,
1120 .copyDebugDesc
= _auth_rights_copy_description
1123 static CFTypeID
auth_rights_get_type_id()
1125 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
1126 static dispatch_once_t onceToken
;
1128 dispatch_once(&onceToken
, ^{
1129 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_rights
);
1135 static auth_rights_t
1136 _auth_rights_create()
1138 auth_rights_t rights
= NULL
;
1140 rights
= (auth_rights_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights
), NULL
);
1141 require(rights
!= NULL
, done
);
1143 rights
->array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1150 auth_rights_create()
1152 auth_rights_t rights
= _auth_rights_create();
1153 require(rights
!= NULL
, done
);
1159 auth_rights_t
auth_rights_create_with_xpc(const xpc_object_t data
)
1161 auth_rights_t rights
= _auth_rights_create();
1162 require(rights
!= NULL
, done
);
1163 require(data
!= NULL
, done
);
1164 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
1166 xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
1168 auth_item_t item
= auth_item_create_with_xpc(value
);
1170 CFArrayAppendValue(rights
->array
, item
);
1171 CFReleaseSafe(item
);
1181 xpc_object_t
auth_rights_export_xpc(auth_rights_t rights
)
1183 xpc_object_t array
= xpc_array_create(NULL
, 0);
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 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
1189 xpc_array_append_value(array
, xpc_data
);
1190 xpc_release_safe(xpc_data
);
1197 _find_right_item(auth_rights_t rights
, const char * key
)
1199 auth_item_t item
= NULL
;
1200 require(key
!= NULL
, done
);
1202 CFIndex count
= CFArrayGetCount(rights
->array
);
1203 for (CFIndex i
= 0; i
< count
; i
++) {
1204 auth_item_t tmp
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1205 if (tmp
&& strcmp(tmp
->data
.name
, key
) == 0) {
1215 void auth_rights_set_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1217 auth_item_t item
= _find_right_item(rights
,key
);
1219 item
->data
.flags
|= flags
;
1223 void auth_rights_clear_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1225 auth_item_t item
= _find_right_item(rights
,key
);
1227 item
->data
.flags
&= ~flags
;
1231 uint32_t auth_rights_get_flags(auth_rights_t rights
, const char *key
)
1233 auth_item_t item
= _find_right_item(rights
,key
);
1235 return item
->data
.flags
;
1241 bool auth_rights_check_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1243 uint32_t current
= auth_rights_get_flags(rights
,key
);
1244 return flags
? (current
& flags
) != 0 : current
== 0;
1247 size_t auth_rights_get_count(auth_rights_t rights
)
1249 return (size_t)CFArrayGetCount(rights
->array
);
1252 void auth_rights_add(auth_rights_t rights
, const char *key
)
1254 auth_item_t item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
1256 CFArrayAppendValue(rights
->array
, item
);
1257 CFReleaseSafe(item
);
1261 bool auth_rights_exist(auth_rights_t rights
, const char *key
)
1263 return (_find_right_item(rights
,key
) != NULL
);
1266 void auth_rights_remove(auth_rights_t rights
, const char *key
)
1268 CFIndex count
= CFArrayGetCount(rights
->array
);
1269 for (CFIndex i
= 0; i
< count
; i
++) {
1270 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1271 if (item
&& strcmp(item
->data
.name
, key
) == 0) {
1272 CFArrayRemoveValueAtIndex(rights
->array
, i
);
1279 void auth_rights_clear(auth_rights_t rights
)
1281 CFArrayRemoveAllValues(rights
->array
);
1285 auth_rights_iterate(auth_rights_t rights
, bool(^iter
)(const char * key
))
1287 bool result
= false;
1289 CFIndex count
= CFArrayGetCount(rights
->array
);
1290 for (CFIndex i
= 0; i
< count
; i
++) {
1291 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1292 result
= iter(item
->data
.name
);