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 item
->bufLen
= sensitiveLength
;
259 item
->data
.valueLength
= sensitiveLength
;
260 item
->data
.value
= calloc(1u, sensitiveLength
);
261 memcpy(item
->data
.value
, value
, sensitiveLength
);
262 memset_s((void *)value
, len
, 0, sensitiveLength
); // clear the sensitive data, memset_s is never optimized away
265 item
->data
.valueLength
= len
;
266 item
->data
.value
= calloc(1u, len
);
267 memcpy(item
->data
.value
, value
, len
);
275 static bool auth_item_crypt_worker(auth_item_t item
, CFDataRef key
, int operation
)
282 if (item
->data
.value
&& item
->data
.valueLength
) {
283 size_t required_length
= 0;
284 CCCryptorStatus status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
285 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
286 item
->data
.value
, item
->data
.valueLength
, NULL
, 0, &required_length
);
287 require(status
== kCCBufferTooSmall
, done
);
289 void *buffer
= calloc(1u, required_length
);
290 status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
291 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
292 item
->data
.value
, item
->data
.valueLength
, buffer
, required_length
, &required_length
);
293 if (status
== kCCSuccess
) {
294 memset(item
->data
.value
, 0, item
->data
.valueLength
);
295 free(item
->data
.value
);
296 item
->data
.value
= buffer
;
297 item
->data
.valueLength
= required_length
;
308 static bool auth_item_decrypt(auth_item_t item
, CFDataRef key
)
310 return auth_item_crypt_worker(item
, key
, kCCDecrypt
);
313 static bool auth_item_encrypt(auth_item_t item
, CFDataRef key
)
315 return auth_item_crypt_worker(item
, key
, kCCEncrypt
);
319 #pragma mark auth_items_t
321 struct _auth_items_s
{
322 __AUTH_BASE_STRUCT_HEADER__
;
324 CFMutableDictionaryRef dictionary
;
325 AuthorizationItemSet set
;
329 _auth_items_finalize(CFTypeRef value
)
331 auth_items_t items
= (auth_items_t
)value
;
333 CFReleaseNull(items
->dictionary
);
334 free_safe(items
->set
.items
)
338 _auth_items_equal(CFTypeRef value1
, CFTypeRef value2
)
340 auth_items_t items1
= (auth_items_t
)value1
;
341 auth_items_t items2
= (auth_items_t
)value2
;
343 return CFEqual(items1
->dictionary
, items2
->dictionary
);
347 auth_items_add_item(auth_items_t items
, auth_item_t item
)
349 CFStringRef cfName
= CFStringCreateWithCString(kCFAllocatorDefault
, item
->data
.name
, kCFStringEncodingUTF8
);
351 CFDictionarySetValue(items
->dictionary
, cfName
, item
);
357 _auth_items_copy_description(CFTypeRef value
)
359 auth_items_t items
= (auth_items_t
)value
;
360 return CFCopyDescription(items
->dictionary
);
363 AUTH_TYPE_INSTANCE(auth_items
,
366 .finalize
= _auth_items_finalize
,
367 .equal
= _auth_items_equal
,
369 .copyFormattingDesc
= NULL
,
370 .copyDebugDesc
= _auth_items_copy_description
373 CFTypeID
auth_items_get_type_id()
375 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
376 static dispatch_once_t onceToken
;
378 dispatch_once(&onceToken
, ^{
379 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_items
);
386 _auth_items_create(bool createDict
)
388 auth_items_t items
= NULL
;
390 items
= (auth_items_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_items_get_type_id(), AUTH_CLASS_SIZE(auth_items
), NULL
);
391 require(items
!= NULL
, done
);
394 items
->dictionary
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
404 auth_items_t items
= NULL
;
406 items
= _auth_items_create(true);
407 require(items
!= NULL
, done
);
414 _auth_items_parse_xpc(auth_items_t items
, const xpc_object_t data
)
417 require(data
!= NULL
, done
);
418 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
420 result
= xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
422 auth_item_t item
= auth_item_create_with_xpc(value
);
424 auth_items_add_item(items
, item
);
435 auth_items_t
auth_items_create_with_xpc(const xpc_object_t data
)
437 auth_items_t items
= NULL
;
439 items
= _auth_items_create(true);
440 require(items
!= NULL
, done
);
442 _auth_items_parse_xpc(items
, data
);
449 auth_items_create_copy(auth_items_t copy
)
451 auth_items_t items
= NULL
;
453 items
= _auth_items_create(false);
454 require(items
!= NULL
, done
);
456 items
->dictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(copy
->dictionary
), copy
->dictionary
);
463 auth_items_get_count(auth_items_t items
)
465 return (size_t)CFDictionaryGetCount(items
->dictionary
);
469 auth_items_export_xpc(auth_items_t items
)
471 xpc_object_t array
= xpc_array_create(NULL
, 0);
473 _cf_dictionary_iterate(items
->dictionary
, ^bool(CFTypeRef key AUTH_UNUSED
, CFTypeRef value
) {
474 auth_item_t item
= (auth_item_t
)value
;
475 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
476 xpc_array_append_value(array
, xpc_data
);
477 xpc_release_safe(xpc_data
);
485 _find_item(auth_items_t items
, const char * key
)
487 auth_item_t item
= NULL
;
488 CFStringRef lookup
= NULL
;
489 require(key
!= NULL
, done
);
491 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
492 require(lookup
!= NULL
, done
);
494 item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
497 CFReleaseSafe(lookup
);
502 auth_items_set_flags(auth_items_t items
, const char *key
, uint32_t flags
)
504 auth_item_t item
= _find_item(items
,key
);
506 item
->data
.flags
|= flags
;
511 auth_items_clear_flags(auth_items_t items
, const char *key
, uint32_t flags
)
513 auth_item_t item
= _find_item(items
,key
);
515 item
->data
.flags
&= ~flags
;
520 auth_items_get_flags(auth_items_t items
, const char *key
)
522 auth_item_t item
= _find_item(items
,key
);
524 return item
->data
.flags
;
531 auth_items_check_flags(auth_items_t items
, const char *key
, uint32_t flags
)
533 // When several bits are set in uint32_t flags, "(current & flags) != 0" checks if ANY flag is set, not all flags!
534 // This odd behavior is currently being relied upon in several places, so be careful when changing / fixing this.
535 // However, this also risks unwanted information leakage in
536 // AuthorizationCopyInfo ==> authorization_copy_info ==> [all info] auth_items_copy_with_flags
537 uint32_t current
= auth_items_get_flags(items
,key
);
538 return flags
? (current
& flags
) != 0 : current
== 0;
542 auth_items_set_key(auth_items_t items
, const char *key
)
544 auth_item_t item
= _find_item(items
,key
);
546 item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
548 auth_items_add_item(items
, item
);
555 auth_items_exist(auth_items_t items
, const char *key
)
557 return _find_item(items
,key
) != NULL
;
561 auth_items_remove(auth_items_t items
, const char *key
)
563 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
564 CFDictionaryRemoveValue(items
->dictionary
, lookup
);
565 CFReleaseSafe(lookup
);
569 auth_items_remove_with_flags(auth_items_t items
, uint32_t flags
)
571 auth_items_iterate(items
, ^bool(const char *key
) {
572 if (auth_items_check_flags(items
, key
, flags
)) {
573 auth_items_remove(items
,key
);
580 auth_items_clear(auth_items_t items
)
582 CFDictionaryRemoveAllValues(items
->dictionary
);
586 auth_items_crypt_worker(auth_items_t items
, CFDataRef encryption_key
, bool(*function
)(auth_item_t
, CFDataRef
))
588 auth_items_iterate(items
, ^bool(const char *key
) {
589 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
590 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
591 function(item
, encryption_key
);
592 CFReleaseSafe(lookup
);
598 auth_items_encrypt(auth_items_t items
, CFDataRef encryption_key
)
600 auth_items_crypt_worker(items
, encryption_key
, auth_item_encrypt
);
604 auth_items_decrypt(auth_items_t items
, CFDataRef encryption_key
)
606 auth_items_crypt_worker(items
, encryption_key
, auth_item_decrypt
);
610 auth_items_copy(auth_items_t items
, auth_items_t src
)
612 auth_items_iterate(src
, ^bool(const char *key
) {
616 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
617 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
618 if (item
) auth_items_add_item(items
, item
);
619 CFReleaseSafe(lookup
);
625 auth_items_content_copy(auth_items_t items
, auth_items_t src
)
627 auth_items_iterate(src
, ^bool(const char *key
) {
628 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
629 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
630 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
631 if (new_item
) auth_items_add_item(items
, new_item
);
632 CFReleaseSafe(lookup
);
633 CFReleaseSafe(new_item
);
639 auth_items_copy_xpc(auth_items_t items
, const xpc_object_t src
)
641 _auth_items_parse_xpc(items
,src
);
645 auth_items_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
647 auth_items_iterate(src
, ^bool(const char *key
) {
648 if (auth_items_check_flags(src
, key
, flags
)) {
649 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
650 if (CFDictionaryContainsKey(items
->dictionary
, lookup
)) {
651 CFDictionaryRemoveValue(items
->dictionary
, lookup
); // we do not want to have preserved unretained key
653 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
654 if (item
) auth_items_add_item(items
, item
);
655 CFReleaseSafe(lookup
);
661 // unlike previous method, this one creates true new copy including their content
663 auth_items_content_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
665 auth_items_iterate(src
, ^bool(const char *key
) {
666 if (auth_items_check_flags(src
, key
, flags
)) {
667 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
668 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
669 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
671 auth_items_add_item(items
, new_item
);
674 CFReleaseSafe(lookup
);
681 auth_items_iterate(auth_items_t items
, auth_items_iterator_t iter
)
684 CFTypeRef
* keys
= NULL
;
685 CFTypeRef
* values
= NULL
;
687 CFIndex count
= CFDictionaryGetCount(items
->dictionary
);
688 keys
= calloc((size_t)count
, sizeof(CFTypeRef
));
689 require(keys
!= NULL
, done
);
691 values
= calloc((size_t)count
, sizeof(CFTypeRef
));
692 require(values
!= NULL
, done
);
694 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
695 for (CFIndex i
= 0; i
< count
; i
++) {
696 auth_item_t item
= (auth_item_t
)values
[i
];
697 result
= iter(item
->data
.name
);
710 auth_items_set_string(auth_items_t items
, const char *key
, const char *value
)
712 assert(value
); // marked non-null
714 size_t valLen
= strlen(value
);
715 auth_item_t item
= _find_item(items
,key
);
716 if (item
&& item
->type
== AI_TYPE_STRING
&& valLen
< item
->bufLen
) {
717 memcpy(item
->data
.value
, value
, valLen
+1); // copy null
718 item
->data
.valueLength
= valLen
;
720 item
= auth_item_create(AI_TYPE_STRING
, key
, value
, valLen
, 0);
722 auth_items_add_item(items
, item
);
729 auth_items_get_string(auth_items_t items
, const char *key
)
731 auth_item_t item
= _find_item(items
,key
);
734 if (!(item
->type
== AI_TYPE_STRING
|| item
->type
== AI_TYPE_UNKNOWN
)) {
735 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
736 item
->data
.name
, item
->type
, AI_TYPE_STRING
);
739 return auth_item_get_string(item
);
746 auth_items_set_data(auth_items_t items
, const char *key
, const void *value
, size_t len
)
748 assert(value
); // marked non-null
751 auth_item_t item
= _find_item(items
,key
);
752 if (item
&& item
->type
== AI_TYPE_DATA
&& len
<= item
->bufLen
) {
753 memcpy(item
->data
.value
, value
, len
);
754 item
->data
.valueLength
= len
;
756 item
= auth_item_create(AI_TYPE_DATA
, key
, value
, len
, 0);
758 auth_items_add_item(items
, item
);
766 auth_items_get_data(auth_items_t items
, const char *key
, size_t *len
)
768 assert(len
); // marked non-null
770 auth_item_t item
= _find_item(items
,key
);
773 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
774 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
775 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
778 *len
= item
->data
.valueLength
;
779 return item
->data
.value
;
786 auth_items_get_data_with_flags(auth_items_t items
, const char *key
, size_t *len
, uint32_t flags
)
788 assert(len
); // marked non-null
790 auth_item_t item
= _find_item(items
,key
);
791 if (item
&& (item
->data
.flags
& flags
) == flags
) {
793 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
794 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
795 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
798 *len
= item
->data
.valueLength
;
800 return item
->data
.value
;
807 auth_items_set_bool(auth_items_t items
, const char *key
, bool value
)
809 auth_item_t item
= _find_item(items
,key
);
810 if (item
&& item
->type
== AI_TYPE_BOOL
) {
811 *(bool*)item
->data
.value
= value
;
813 item
= auth_item_create(AI_TYPE_BOOL
, key
, &value
, sizeof(bool), 0);
815 auth_items_add_item(items
, item
);
822 auth_items_get_bool(auth_items_t items
, const char *key
)
824 auth_item_t item
= _find_item(items
,key
);
827 if (!(item
->type
== AI_TYPE_BOOL
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(bool))) {
828 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
829 item
->data
.name
, item
->type
, AI_TYPE_BOOL
, item
->data
.valueLength
, sizeof(bool));
832 if (item
->type
== AI_TYPE_STRING
) {
833 return atoi(auth_item_get_string(item
));
836 require(item
->data
.value
!= NULL
, done
);
837 require(item
->data
.valueLength
== sizeof(bool), done
);
839 return *(bool*)item
->data
.value
;
847 auth_items_set_int(auth_items_t items
, const char *key
, int32_t value
)
849 auth_item_t item
= _find_item(items
,key
);
850 if (item
&& item
->type
== AI_TYPE_INT
) {
851 *(int32_t*)item
->data
.value
= value
;
853 item
= auth_item_create(AI_TYPE_INT
, key
, &value
, sizeof(int32_t), 0);
855 auth_items_add_item(items
, item
);
862 auth_items_get_int(auth_items_t items
, const char *key
)
864 auth_item_t item
= _find_item(items
,key
);
867 if (!(item
->type
==AI_TYPE_INT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int32_t))) {
868 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
869 item
->data
.name
, item
->type
, AI_TYPE_INT
, item
->data
.valueLength
, sizeof(int32_t));
872 if (item
->type
== AI_TYPE_STRING
) {
873 return atoi(auth_item_get_string(item
));
876 require(item
->data
.value
!= NULL
, done
);
877 require(item
->data
.valueLength
== sizeof(int32_t), done
);
879 return *(int32_t*)item
->data
.value
;
887 auth_items_set_uint(auth_items_t items
, const char *key
, uint32_t value
)
889 auth_item_t item
= _find_item(items
,key
);
890 if (item
&& item
->type
== AI_TYPE_UINT
) {
891 *(uint32_t*)item
->data
.value
= value
;
893 item
= auth_item_create(AI_TYPE_UINT
, key
, &value
, sizeof(uint32_t), 0);
895 auth_items_add_item(items
, item
);
902 auth_items_get_uint(auth_items_t items
, const char *key
)
904 auth_item_t item
= _find_item(items
,key
);
907 if (!(item
->type
==AI_TYPE_UINT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint32_t))) {
908 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
909 item
->data
.name
, item
->type
, AI_TYPE_UINT
, item
->data
.valueLength
, sizeof(uint32_t));
912 if (item
->type
== AI_TYPE_STRING
) {
913 return (uint32_t)atoi(auth_item_get_string(item
));
916 require(item
->data
.value
!= NULL
, done
);
917 require(item
->data
.valueLength
== sizeof(uint32_t), done
);
919 return *(uint32_t*)item
->data
.value
;
927 auth_items_set_int64(auth_items_t items
, const char *key
, int64_t value
)
929 auth_item_t item
= _find_item(items
,key
);
930 if (item
&& item
->type
== AI_TYPE_INT64
) {
931 *(int64_t*)item
->data
.value
= value
;
933 item
= auth_item_create(AI_TYPE_INT64
, key
, &value
, sizeof(int64_t), 0);
935 auth_items_add_item(items
, item
);
942 auth_items_get_int64(auth_items_t items
, const char *key
)
944 auth_item_t item
= _find_item(items
,key
);
947 if (!(item
->type
==AI_TYPE_INT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int64_t))) {
948 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
949 item
->data
.name
, item
->type
, AI_TYPE_INT64
, item
->data
.valueLength
, sizeof(int64_t));
952 if (item
->type
== AI_TYPE_STRING
) {
953 return atoll(auth_item_get_string(item
));
956 require(item
->data
.value
!= NULL
, done
);
957 require(item
->data
.valueLength
== sizeof(int64_t), done
);
959 return *(int64_t*)item
->data
.value
;
967 auth_items_set_uint64(auth_items_t items
, const char *key
, uint64_t value
)
969 auth_item_t item
= _find_item(items
,key
);
970 if (item
&& item
->type
== AI_TYPE_UINT64
) {
971 *(uint64_t*)item
->data
.value
= value
;
973 item
= auth_item_create(AI_TYPE_UINT64
, key
, &value
, sizeof(uint64_t), 0);
975 auth_items_add_item(items
, item
);
982 auth_items_get_uint64(auth_items_t items
, const char *key
)
984 auth_item_t item
= _find_item(items
,key
);
987 if (!(item
->type
==AI_TYPE_UINT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint64_t))) {
988 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
989 item
->data
.name
, item
->type
, AI_TYPE_UINT64
, item
->data
.valueLength
, sizeof(uint64_t));
992 if (item
->type
== AI_TYPE_STRING
) {
993 return (uint64_t)atoll(auth_item_get_string(item
));
996 require(item
->data
.value
!= NULL
, done
);
997 require(item
->data
.valueLength
== sizeof(uint64_t), done
);
999 return *(uint64_t*)item
->data
.value
;
1006 void auth_items_set_double(auth_items_t items
, const char *key
, double value
)
1008 auth_item_t item
= _find_item(items
,key
);
1009 if (item
&& item
->type
== AI_TYPE_DOUBLE
) {
1010 *(double*)item
->data
.value
= value
;
1012 item
= auth_item_create(AI_TYPE_DOUBLE
, key
, &value
, sizeof(double), 0);
1014 auth_items_add_item(items
, item
);
1020 double auth_items_get_double(auth_items_t items
, const char *key
)
1022 auth_item_t item
= _find_item(items
,key
);
1025 if (!(item
->type
==AI_TYPE_DOUBLE
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(double))) {
1026 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
1027 item
->data
.name
, item
->type
, AI_TYPE_DOUBLE
, item
->data
.valueLength
, sizeof(double));
1030 if (item
->type
== AI_TYPE_STRING
) {
1031 return atof(auth_item_get_string(item
));
1034 require(item
->data
.value
!= NULL
, done
);
1035 require(item
->data
.valueLength
== sizeof(double), done
);
1037 return *(double*)item
->data
.value
;
1044 uint32_t auth_items_get_type(auth_items_t items
, const char *key
)
1046 auth_item_t item
= _find_item(items
,key
);
1051 return AI_TYPE_UNKNOWN
;
1054 size_t auth_items_get_length(auth_items_t items
, const char *key
)
1056 auth_item_t item
= _find_item(items
,key
);
1058 return item
->data
.valueLength
;
1064 void auth_items_set_value(auth_items_t items
, const char *key
, uint32_t type
, uint32_t flags
, const void *value
, size_t len
)
1066 auth_item_t item
= auth_item_create(type
, key
, value
, len
, flags
);
1068 auth_items_add_item(items
, item
);
1074 #pragma mark auth_rights_t
1076 struct _auth_rights_s
{
1077 __AUTH_BASE_STRUCT_HEADER__
;
1079 CFMutableArrayRef array
;
1083 _auth_rights_finalize(CFTypeRef value
)
1085 auth_rights_t rights
= (auth_rights_t
)value
;
1087 CFReleaseNull(rights
->array
);
1091 _auth_rights_equal(CFTypeRef value1
, CFTypeRef value2
)
1093 auth_rights_t rights1
= (auth_rights_t
)value1
;
1094 auth_rights_t rights2
= (auth_rights_t
)value2
;
1096 return CFEqual(rights1
->array
, rights2
->array
);
1100 _auth_rights_copy_description(CFTypeRef value
)
1102 auth_rights_t rights
= (auth_rights_t
)value
;
1103 return CFCopyDescription(rights
->array
);
1106 AUTH_TYPE_INSTANCE(auth_rights
,
1109 .finalize
= _auth_rights_finalize
,
1110 .equal
= _auth_rights_equal
,
1112 .copyFormattingDesc
= NULL
,
1113 .copyDebugDesc
= _auth_rights_copy_description
1116 static CFTypeID
auth_rights_get_type_id()
1118 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
1119 static dispatch_once_t onceToken
;
1121 dispatch_once(&onceToken
, ^{
1122 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_rights
);
1128 static auth_rights_t
1129 _auth_rights_create()
1131 auth_rights_t rights
= NULL
;
1133 rights
= (auth_rights_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights
), NULL
);
1134 require(rights
!= NULL
, done
);
1136 rights
->array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1143 auth_rights_create()
1145 auth_rights_t rights
= _auth_rights_create();
1146 require(rights
!= NULL
, done
);
1152 auth_rights_t
auth_rights_create_with_xpc(const xpc_object_t data
)
1154 auth_rights_t rights
= _auth_rights_create();
1155 require(rights
!= NULL
, done
);
1156 require(data
!= NULL
, done
);
1157 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
1159 xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
1161 auth_item_t item
= auth_item_create_with_xpc(value
);
1163 CFArrayAppendValue(rights
->array
, item
);
1164 CFReleaseSafe(item
);
1174 xpc_object_t
auth_rights_export_xpc(auth_rights_t rights
)
1176 xpc_object_t array
= xpc_array_create(NULL
, 0);
1178 CFIndex count
= CFArrayGetCount(rights
->array
);
1179 for (CFIndex i
= 0; i
< count
; i
++) {
1180 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1181 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
1182 xpc_array_append_value(array
, xpc_data
);
1183 xpc_release_safe(xpc_data
);
1190 _find_right_item(auth_rights_t rights
, const char * key
)
1192 auth_item_t item
= NULL
;
1193 require(key
!= NULL
, done
);
1195 CFIndex count
= CFArrayGetCount(rights
->array
);
1196 for (CFIndex i
= 0; i
< count
; i
++) {
1197 auth_item_t tmp
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1198 if (tmp
&& strcmp(tmp
->data
.name
, key
) == 0) {
1208 void auth_rights_set_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1210 auth_item_t item
= _find_right_item(rights
,key
);
1212 item
->data
.flags
|= flags
;
1216 void auth_rights_clear_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1218 auth_item_t item
= _find_right_item(rights
,key
);
1220 item
->data
.flags
&= ~flags
;
1224 uint32_t auth_rights_get_flags(auth_rights_t rights
, const char *key
)
1226 auth_item_t item
= _find_right_item(rights
,key
);
1228 return item
->data
.flags
;
1234 bool auth_rights_check_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1236 uint32_t current
= auth_rights_get_flags(rights
,key
);
1237 return flags
? (current
& flags
) != 0 : current
== 0;
1240 size_t auth_rights_get_count(auth_rights_t rights
)
1242 return (size_t)CFArrayGetCount(rights
->array
);
1245 void auth_rights_add(auth_rights_t rights
, const char *key
)
1247 auth_item_t item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
1249 CFArrayAppendValue(rights
->array
, item
);
1250 CFReleaseSafe(item
);
1254 bool auth_rights_exist(auth_rights_t rights
, const char *key
)
1256 return (_find_right_item(rights
,key
) != NULL
);
1259 void auth_rights_remove(auth_rights_t rights
, const char *key
)
1261 CFIndex count
= CFArrayGetCount(rights
->array
);
1262 for (CFIndex i
= 0; i
< count
; i
++) {
1263 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1264 if (item
&& strcmp(item
->data
.name
, key
) == 0) {
1265 CFArrayRemoveValueAtIndex(rights
->array
, i
);
1272 void auth_rights_clear(auth_rights_t rights
)
1274 CFArrayRemoveAllValues(rights
->array
);
1278 auth_rights_iterate(auth_rights_t rights
, bool(^iter
)(const char * key
))
1280 bool result
= false;
1282 CFIndex count
= CFArrayGetCount(rights
->array
);
1283 for (CFIndex i
= 0; i
< count
; i
++) {
1284 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1285 result
= iter(item
->data
.name
);