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
;
31 auth_item_get_string(auth_item_t item
)
33 if (item
->bufLen
<= item
->data
.valueLength
) {
34 item
->bufLen
= item
->data
.valueLength
+1; // make sure buffer has a null char
35 item
->data
.value
= realloc(item
->data
.value
, item
->bufLen
);
36 if (item
->data
.value
== NULL
) {
37 // this is added to prevent running off into random memory if a string buffer doesn't have a null char
38 os_log_error(AUTHD_LOG
, "items: realloc failed");
41 ((uint8_t*)item
->data
.value
)[item
->bufLen
-1] = '\0';
43 return item
->data
.value
;
47 auth_item_get_cf_key(auth_item_t item
)
50 item
->cfKey
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, item
->data
.name
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
55 static AuthorizationItem
*
56 auth_item_get_auth_item(auth_item_t item
)
62 auth_item_copy_auth_item_xpc(auth_item_t item
)
64 xpc_object_t xpc_data
= xpc_dictionary_create(NULL
, NULL
, 0);
65 xpc_dictionary_set_string(xpc_data
, AUTH_XPC_ITEM_NAME
, item
->data
.name
);
66 if (item
->data
.value
) {
67 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
68 bool sensitive
= strcmp(item
->data
.name
, "password") == 0;
70 vm_address_t vmBytes
= 0;
71 size_t xpcOutOfBandBlockSize
= (item
->data
.valueLength
> 32768 ? item
->data
.valueLength
: 32768); // min 16K on 64-bit systems and 12K on 32-bit systems
72 vm_allocate(mach_task_self(), &vmBytes
, xpcOutOfBandBlockSize
, VM_FLAGS_ANYWHERE
);
73 memcpy((void *)vmBytes
, item
->data
.value
, item
->data
.valueLength
);
74 dispatch_data_t dispData
= dispatch_data_create((void *)vmBytes
, xpcOutOfBandBlockSize
, DISPATCH_TARGET_QUEUE_DEFAULT
, DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE
); // out-of-band mapping
75 xpc_object_t xpcData
= xpc_data_create_with_dispatch_data(dispData
);
76 dispatch_release(dispData
);
77 xpc_dictionary_set_value(xpc_data
, AUTH_XPC_ITEM_VALUE
, xpcData
);
79 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
, item
->data
.valueLength
);
81 xpc_dictionary_set_data(xpc_data
, AUTH_XPC_ITEM_VALUE
, item
->data
.value
, item
->data
.valueLength
);
84 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_FLAGS
, item
->data
.flags
);
85 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_TYPE
, item
->type
);
90 _auth_item_finalize(CFTypeRef value
)
92 auth_item_t item
= (auth_item_t
)value
;
94 CFReleaseNull(item
->cfKey
);
96 if (item
->data
.name
) {
97 free((void*)item
->data
.name
);
98 /* cannot set item->data.name to NULL because item->data.name is non-nullable public API (rdar://problem/32235322)
99 * cannot leave item->data.name pointing to original data (rdar://problem/31006596)
100 * => suppress the warning */
101 #ifndef __clang_analyzer__
102 item
->data
.name
= NULL
;
106 if (item
->data
.value
) {
107 memset(item
->data
.value
, 0, item
->data
.valueLength
);
108 free_safe(item
->data
.value
);
113 _auth_item_equal(CFTypeRef value1
, CFTypeRef value2
)
115 return (CFHash(value1
) == CFHash(value2
));
119 _auth_item_copy_description(CFTypeRef value
)
122 auth_item_t item
= (auth_item_t
)value
;
125 static size_t passLen
= strlen(kAuthorizationEnvironmentPassword
);
126 if (strncasecmp(item
->data
.name
, kAuthorizationEnvironmentPassword
, passLen
) == 0) {
131 CFMutableStringRef desc
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
132 CFStringAppendFormat(desc
, NULL
, CFSTR("auth_item: %s, type=%i, length=%li, flags=%x"),
133 item
->data
.name
, item
->type
,
134 hidden
? 0 : item
->data
.valueLength
, (unsigned int)item
->data
.flags
);
136 switch (item
->type
) {
138 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%s"), hidden
? "(hidden)" : auth_item_get_string(item
));
141 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(int32_t*)item
->data
.value
);
144 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%u"), *(uint32_t*)item
->data
.value
);
147 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%lli"), *(int64_t*)item
->data
.value
);
150 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%llu"), *(uint64_t*)item
->data
.value
);
153 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(bool*)item
->data
.value
);
156 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%f"), *(double*)item
->data
.value
);
159 case AI_TYPE_UNKNOWN
:
161 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=(hidden)"));
163 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=0x"));
164 size_t i
= item
->data
.valueLength
< 10 ? item
->data
.valueLength
: 10;
165 uint8_t * data
= item
->data
.value
;
167 CFStringAppendFormat(desc
, NULL
, CFSTR("%02x"), data
[i
-1]);
178 _auth_item_hash(CFTypeRef value
)
180 auth_item_t item
= (auth_item_t
)value
;
181 uint64_t crc
= crc64_init();
182 crc
= crc64_update(crc
, item
->data
.name
, strlen(item
->data
.name
));
183 if (item
->data
.value
) {
184 crc
= crc64_update(crc
, item
->data
.value
, item
->data
.valueLength
);
186 crc
= crc64_update(crc
, &item
->data
.flags
, sizeof(item
->data
.flags
));
188 crc
= crc64_final(crc
);
189 return (CFHashCode
)crc
;
192 AUTH_TYPE_INSTANCE(auth_item
,
195 .finalize
= _auth_item_finalize
,
196 .equal
= _auth_item_equal
,
197 .hash
= _auth_item_hash
,
198 .copyFormattingDesc
= NULL
,
199 .copyDebugDesc
= _auth_item_copy_description
202 static CFTypeID
auth_item_get_type_id() {
203 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
204 static dispatch_once_t onceToken
;
206 dispatch_once(&onceToken
, ^{
207 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_item
);
216 auth_item_t item
= NULL
;
218 item
= (auth_item_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_item_get_type_id(), AUTH_CLASS_SIZE(auth_item
), NULL
);
219 require(item
!= NULL
, done
);
226 auth_item_create(uint32_t type
, const char * name
, const void * value
, size_t valueLen
, uint32_t flags
)
228 auth_item_t item
= NULL
;
229 require(name
!= NULL
, done
);
231 item
= _auth_item_create();
232 require(item
!= NULL
, done
);
235 item
->data
.flags
= flags
;
236 item
->data
.name
= _copy_string(name
);
237 item
->data
.valueLength
= valueLen
;
238 item
->bufLen
= valueLen
;
240 if (item
->type
== AI_TYPE_STRING
) {
242 item
->data
.value
= calloc(1u, item
->bufLen
);
243 } else if (valueLen
) {
244 item
->data
.value
= calloc(1u, item
->bufLen
);
247 memcpy(item
->data
.value
, value
, valueLen
);
256 auth_item_create_with_xpc(xpc_object_t data
)
258 auth_item_t item
= NULL
;
259 require(data
!= NULL
, done
);
260 require(xpc_get_type(data
) == XPC_TYPE_DICTIONARY
, done
);
261 require(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
) != NULL
, done
);
263 item
= _auth_item_create();
264 require(item
!= NULL
, done
);
266 item
->data
.name
= _copy_string(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
));
267 item
->data
.flags
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_FLAGS
);
268 item
->type
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_TYPE
);
271 const void * value
= xpc_dictionary_get_data(data
, AUTH_XPC_ITEM_VALUE
, &len
);
273 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
274 bool sensitive
= xpc_dictionary_get_value(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
276 size_t sensitiveLength
= (size_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
277 item
->bufLen
= sensitiveLength
;
278 item
->data
.valueLength
= sensitiveLength
;
279 item
->data
.value
= calloc(1u, sensitiveLength
);
280 memcpy(item
->data
.value
, value
, sensitiveLength
);
281 memset_s((void *)value
, len
, 0, sensitiveLength
); // clear the sensitive data, memset_s is never optimized away
284 item
->data
.valueLength
= len
;
285 item
->data
.value
= calloc(1u, len
);
286 memcpy(item
->data
.value
, value
, len
);
294 static bool auth_item_crypt_worker(auth_item_t item
, CFDataRef key
, int operation
)
301 if (item
->data
.value
&& item
->data
.valueLength
) {
302 size_t required_length
= 0;
303 CCCryptorStatus status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
304 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
305 item
->data
.value
, item
->data
.valueLength
, NULL
, 0, &required_length
);
306 require(status
== kCCBufferTooSmall
, done
);
308 void *buffer
= calloc(1u, required_length
);
309 status
= CCCrypt(operation
, kCCAlgorithmAES
, kCCOptionPKCS7Padding
,
310 CFDataGetBytePtr(key
), CFDataGetLength(key
), NULL
,
311 item
->data
.value
, item
->data
.valueLength
, buffer
, required_length
, &required_length
);
312 if (status
== kCCSuccess
) {
313 memset(item
->data
.value
, 0, item
->data
.valueLength
);
314 free(item
->data
.value
);
315 item
->data
.value
= buffer
;
316 item
->data
.valueLength
= required_length
;
327 static bool auth_item_decrypt(auth_item_t item
, CFDataRef key
)
329 return auth_item_crypt_worker(item
, key
, kCCDecrypt
);
332 static bool auth_item_encrypt(auth_item_t item
, CFDataRef key
)
334 return auth_item_crypt_worker(item
, key
, kCCEncrypt
);
338 #pragma mark auth_items_t
340 struct _auth_items_s
{
341 __AUTH_BASE_STRUCT_HEADER__
;
343 CFMutableDictionaryRef dictionary
;
344 AuthorizationItemSet set
;
348 _auth_items_finalize(CFTypeRef value
)
350 auth_items_t items
= (auth_items_t
)value
;
352 CFReleaseNull(items
->dictionary
);
353 free_safe(items
->set
.items
)
357 _auth_items_equal(CFTypeRef value1
, CFTypeRef value2
)
359 auth_items_t items1
= (auth_items_t
)value1
;
360 auth_items_t items2
= (auth_items_t
)value2
;
362 return CFEqual(items1
->dictionary
, items2
->dictionary
);
366 _auth_items_copy_description(CFTypeRef value
)
368 auth_items_t items
= (auth_items_t
)value
;
369 return CFCopyDescription(items
->dictionary
);
372 AUTH_TYPE_INSTANCE(auth_items
,
375 .finalize
= _auth_items_finalize
,
376 .equal
= _auth_items_equal
,
378 .copyFormattingDesc
= NULL
,
379 .copyDebugDesc
= _auth_items_copy_description
382 CFTypeID
auth_items_get_type_id()
384 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
385 static dispatch_once_t onceToken
;
387 dispatch_once(&onceToken
, ^{
388 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_items
);
395 _auth_items_create(bool createDict
)
397 auth_items_t items
= NULL
;
399 items
= (auth_items_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_items_get_type_id(), AUTH_CLASS_SIZE(auth_items
), NULL
);
400 require(items
!= NULL
, done
);
403 items
->dictionary
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
413 auth_items_t items
= NULL
;
415 items
= _auth_items_create(true);
416 require(items
!= NULL
, done
);
423 _auth_items_parse_xpc(auth_items_t items
, const xpc_object_t data
)
426 require(data
!= NULL
, done
);
427 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
429 result
= xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
431 auth_item_t item
= auth_item_create_with_xpc(value
);
433 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
444 auth_items_t
auth_items_create_with_xpc(const xpc_object_t data
)
446 auth_items_t items
= NULL
;
448 items
= _auth_items_create(true);
449 require(items
!= NULL
, done
);
451 _auth_items_parse_xpc(items
, data
);
458 auth_items_create_copy(auth_items_t copy
)
460 auth_items_t items
= NULL
;
462 items
= _auth_items_create(false);
463 require(items
!= NULL
, done
);
465 items
->dictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(copy
->dictionary
), copy
->dictionary
);
472 auth_items_get_count(auth_items_t items
)
474 return (size_t)CFDictionaryGetCount(items
->dictionary
);
477 AuthorizationItemSet
*
478 auth_items_get_item_set(auth_items_t items
)
480 uint32_t count
= (uint32_t)CFDictionaryGetCount(items
->dictionary
);
482 size_t size
= count
* sizeof(AuthorizationItem
);
483 if (items
->set
.items
== NULL
) {
484 items
->set
.items
= calloc(1u, size
);
485 require(items
->set
.items
!= NULL
, done
);
487 if (count
> items
->set
.count
) {
488 items
->set
.items
= realloc(items
->set
.items
, size
);
489 require_action(items
->set
.items
!= NULL
, done
, items
->set
.count
= 0);
492 items
->set
.count
= count
;
493 CFTypeRef keys
[count
], values
[count
];
494 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
495 for (uint32_t i
= 0; i
< count
; i
++) {
496 auth_item_t item
= (auth_item_t
)values
[i
];
497 items
->set
.items
[i
] = *auth_item_get_auth_item(item
);
500 items
->set
.count
= 0;
508 auth_items_export_xpc(auth_items_t items
)
510 xpc_object_t array
= xpc_array_create(NULL
, 0);
512 _cf_dictionary_iterate(items
->dictionary
, ^bool(CFTypeRef key AUTH_UNUSED
, CFTypeRef value
) {
513 auth_item_t item
= (auth_item_t
)value
;
514 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
515 xpc_array_append_value(array
, xpc_data
);
516 xpc_release_safe(xpc_data
);
524 _find_item(auth_items_t items
, const char * key
)
526 auth_item_t item
= NULL
;
527 CFStringRef lookup
= NULL
;
528 require(key
!= NULL
, done
);
530 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
531 require(lookup
!= NULL
, done
);
533 item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
536 CFReleaseSafe(lookup
);
541 auth_items_set_flags(auth_items_t items
, const char *key
, uint32_t flags
)
543 auth_item_t item
= _find_item(items
,key
);
545 item
->data
.flags
|= flags
;
550 auth_items_clear_flags(auth_items_t items
, const char *key
, uint32_t flags
)
552 auth_item_t item
= _find_item(items
,key
);
554 item
->data
.flags
&= ~flags
;
559 auth_items_get_flags(auth_items_t items
, const char *key
)
561 auth_item_t item
= _find_item(items
,key
);
563 return item
->data
.flags
;
570 auth_items_check_flags(auth_items_t items
, const char *key
, uint32_t flags
)
572 // When several bits are set in uint32_t flags, "(current & flags) != 0" checks if ANY flag is set, not all flags!
573 // This odd behavior is currently being relied upon in several places, so be careful when changing / fixing this.
574 // However, this also risks unwanted information leakage in
575 // AuthorizationCopyInfo ==> authorization_copy_info ==> [all info] auth_items_copy_with_flags
576 uint32_t current
= auth_items_get_flags(items
,key
);
577 return flags
? (current
& flags
) != 0 : current
== 0;
581 auth_items_set_key(auth_items_t items
, const char *key
)
583 auth_item_t item
= _find_item(items
,key
);
585 item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
587 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
594 auth_items_exist(auth_items_t items
, const char *key
)
596 return _find_item(items
,key
) != NULL
;
600 auth_items_remove(auth_items_t items
, const char *key
)
602 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
603 CFDictionaryRemoveValue(items
->dictionary
, lookup
);
604 CFReleaseSafe(lookup
);
608 auth_items_remove_with_flags(auth_items_t items
, uint32_t flags
)
610 auth_items_iterate(items
, ^bool(const char *key
) {
611 if (auth_items_check_flags(items
, key
, flags
)) {
612 auth_items_remove(items
,key
);
619 auth_items_clear(auth_items_t items
)
621 CFDictionaryRemoveAllValues(items
->dictionary
);
625 auth_items_crypt_worker(auth_items_t items
, CFDataRef encryption_key
, bool(*function
)(auth_item_t
, CFDataRef
))
627 auth_items_iterate(items
, ^bool(const char *key
) {
628 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
629 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
630 function(item
, encryption_key
);
631 CFReleaseSafe(lookup
);
637 auth_items_encrypt(auth_items_t items
, CFDataRef encryption_key
)
639 auth_items_crypt_worker(items
, encryption_key
, auth_item_encrypt
);
643 auth_items_decrypt(auth_items_t items
, CFDataRef encryption_key
)
645 auth_items_crypt_worker(items
, encryption_key
, auth_item_decrypt
);
649 auth_items_copy(auth_items_t items
, auth_items_t src
)
651 auth_items_iterate(src
, ^bool(const char *key
) {
655 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
656 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
657 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
658 CFReleaseSafe(lookup
);
664 auth_items_content_copy(auth_items_t items
, auth_items_t src
)
666 auth_items_iterate(src
, ^bool(const char *key
) {
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 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(new_item
), new_item
);
672 CFReleaseSafe(lookup
);
673 CFReleaseSafe(new_item
);
679 auth_items_copy_xpc(auth_items_t items
, const xpc_object_t src
)
681 _auth_items_parse_xpc(items
,src
);
685 auth_items_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
687 auth_items_iterate(src
, ^bool(const char *key
) {
688 if (auth_items_check_flags(src
, key
, flags
)) {
689 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
690 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
691 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
692 CFReleaseSafe(lookup
);
698 // unlike previous method, this one creates true new copy including their content
700 auth_items_content_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
702 auth_items_iterate(src
, ^bool(const char *key
) {
703 if (auth_items_check_flags(src
, key
, flags
)) {
704 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
705 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
706 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
708 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(new_item
), new_item
);
709 CFReleaseSafe(lookup
);
710 CFReleaseSafe(new_item
);
717 auth_items_iterate(auth_items_t items
, auth_items_iterator_t iter
)
720 CFTypeRef
* keys
= NULL
;
721 CFTypeRef
* values
= NULL
;
723 CFIndex count
= CFDictionaryGetCount(items
->dictionary
);
724 keys
= calloc((size_t)count
, sizeof(CFTypeRef
));
725 require(keys
!= NULL
, done
);
727 values
= calloc((size_t)count
, sizeof(CFTypeRef
));
728 require(values
!= NULL
, done
);
730 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
731 for (CFIndex i
= 0; i
< count
; i
++) {
732 auth_item_t item
= (auth_item_t
)values
[i
];
733 result
= iter(item
->data
.name
);
746 auth_items_set_string(auth_items_t items
, const char *key
, const char *value
)
748 assert(value
); // marked non-null
750 size_t valLen
= strlen(value
);
751 auth_item_t item
= _find_item(items
,key
);
752 if (item
&& item
->type
== AI_TYPE_STRING
&& valLen
< item
->bufLen
) {
753 memcpy(item
->data
.value
, value
, valLen
+1); // copy null
754 item
->data
.valueLength
= valLen
;
756 item
= auth_item_create(AI_TYPE_STRING
, key
, value
, valLen
, 0);
758 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
765 auth_items_get_string(auth_items_t items
, const char *key
)
767 auth_item_t item
= _find_item(items
,key
);
770 if (!(item
->type
== AI_TYPE_STRING
|| item
->type
== AI_TYPE_UNKNOWN
)) {
771 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
772 item
->data
.name
, item
->type
, AI_TYPE_STRING
);
775 return auth_item_get_string(item
);
782 auth_items_set_data(auth_items_t items
, const char *key
, const void *value
, size_t len
)
784 assert(value
); // marked non-null
787 auth_item_t item
= _find_item(items
,key
);
788 if (item
&& item
->type
== AI_TYPE_DATA
&& len
<= item
->bufLen
) {
789 memcpy(item
->data
.value
, value
, len
);
790 item
->data
.valueLength
= len
;
792 item
= auth_item_create(AI_TYPE_DATA
, key
, value
, len
, 0);
794 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
802 auth_items_get_data(auth_items_t items
, const char *key
, size_t *len
)
804 assert(len
); // marked non-null
806 auth_item_t item
= _find_item(items
,key
);
809 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
810 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
811 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
814 *len
= item
->data
.valueLength
;
815 return item
->data
.value
;
822 auth_items_get_data_with_flags(auth_items_t items
, const char *key
, size_t *len
, uint32_t flags
)
824 assert(len
); // marked non-null
826 auth_item_t item
= _find_item(items
,key
);
827 if (item
&& (item
->data
.flags
& flags
) == flags
) {
829 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
830 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
831 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
834 *len
= item
->data
.valueLength
;
836 return item
->data
.value
;
843 auth_items_set_bool(auth_items_t items
, const char *key
, bool value
)
845 auth_item_t item
= _find_item(items
,key
);
846 if (item
&& item
->type
== AI_TYPE_BOOL
) {
847 *(bool*)item
->data
.value
= value
;
849 item
= auth_item_create(AI_TYPE_BOOL
, key
, &value
, sizeof(bool), 0);
851 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
858 auth_items_get_bool(auth_items_t items
, const char *key
)
860 auth_item_t item
= _find_item(items
,key
);
863 if (!(item
->type
== AI_TYPE_BOOL
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(bool))) {
864 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
865 item
->data
.name
, item
->type
, AI_TYPE_BOOL
, item
->data
.valueLength
, sizeof(bool));
868 if (item
->type
== AI_TYPE_STRING
) {
869 return atoi(auth_item_get_string(item
));
872 require(item
->data
.value
!= NULL
, done
);
873 require(item
->data
.valueLength
== sizeof(bool), done
);
875 return *(bool*)item
->data
.value
;
883 auth_items_set_int(auth_items_t items
, const char *key
, int32_t value
)
885 auth_item_t item
= _find_item(items
,key
);
886 if (item
&& item
->type
== AI_TYPE_INT
) {
887 *(int32_t*)item
->data
.value
= value
;
889 item
= auth_item_create(AI_TYPE_INT
, key
, &value
, sizeof(int32_t), 0);
891 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
898 auth_items_get_int(auth_items_t items
, const char *key
)
900 auth_item_t item
= _find_item(items
,key
);
903 if (!(item
->type
==AI_TYPE_INT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int32_t))) {
904 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
905 item
->data
.name
, item
->type
, AI_TYPE_INT
, item
->data
.valueLength
, sizeof(int32_t));
908 if (item
->type
== AI_TYPE_STRING
) {
909 return atoi(auth_item_get_string(item
));
912 require(item
->data
.value
!= NULL
, done
);
913 require(item
->data
.valueLength
== sizeof(int32_t), done
);
915 return *(int32_t*)item
->data
.value
;
923 auth_items_set_uint(auth_items_t items
, const char *key
, uint32_t value
)
925 auth_item_t item
= _find_item(items
,key
);
926 if (item
&& item
->type
== AI_TYPE_UINT
) {
927 *(uint32_t*)item
->data
.value
= value
;
929 item
= auth_item_create(AI_TYPE_UINT
, key
, &value
, sizeof(uint32_t), 0);
931 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
938 auth_items_get_uint(auth_items_t items
, const char *key
)
940 auth_item_t item
= _find_item(items
,key
);
943 if (!(item
->type
==AI_TYPE_UINT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint32_t))) {
944 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
945 item
->data
.name
, item
->type
, AI_TYPE_UINT
, item
->data
.valueLength
, sizeof(uint32_t));
948 if (item
->type
== AI_TYPE_STRING
) {
949 return (uint32_t)atoi(auth_item_get_string(item
));
952 require(item
->data
.value
!= NULL
, done
);
953 require(item
->data
.valueLength
== sizeof(uint32_t), done
);
955 return *(uint32_t*)item
->data
.value
;
963 auth_items_set_int64(auth_items_t items
, const char *key
, int64_t value
)
965 auth_item_t item
= _find_item(items
,key
);
966 if (item
&& item
->type
== AI_TYPE_INT64
) {
967 *(int64_t*)item
->data
.value
= value
;
969 item
= auth_item_create(AI_TYPE_INT64
, key
, &value
, sizeof(int64_t), 0);
971 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
978 auth_items_get_int64(auth_items_t items
, const char *key
)
980 auth_item_t item
= _find_item(items
,key
);
983 if (!(item
->type
==AI_TYPE_INT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int64_t))) {
984 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
985 item
->data
.name
, item
->type
, AI_TYPE_INT64
, item
->data
.valueLength
, sizeof(int64_t));
988 if (item
->type
== AI_TYPE_STRING
) {
989 return atoll(auth_item_get_string(item
));
992 require(item
->data
.value
!= NULL
, done
);
993 require(item
->data
.valueLength
== sizeof(int64_t), done
);
995 return *(int64_t*)item
->data
.value
;
1003 auth_items_set_uint64(auth_items_t items
, const char *key
, uint64_t value
)
1005 auth_item_t item
= _find_item(items
,key
);
1006 if (item
&& item
->type
== AI_TYPE_UINT64
) {
1007 *(uint64_t*)item
->data
.value
= value
;
1009 item
= auth_item_create(AI_TYPE_UINT64
, key
, &value
, sizeof(uint64_t), 0);
1011 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
1012 CFReleaseSafe(item
);
1018 auth_items_get_uint64(auth_items_t items
, const char *key
)
1020 auth_item_t item
= _find_item(items
,key
);
1023 if (!(item
->type
==AI_TYPE_UINT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint64_t))) {
1024 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
1025 item
->data
.name
, item
->type
, AI_TYPE_UINT64
, item
->data
.valueLength
, sizeof(uint64_t));
1028 if (item
->type
== AI_TYPE_STRING
) {
1029 return (uint64_t)atoll(auth_item_get_string(item
));
1032 require(item
->data
.value
!= NULL
, done
);
1033 require(item
->data
.valueLength
== sizeof(uint64_t), done
);
1035 return *(uint64_t*)item
->data
.value
;
1042 void auth_items_set_double(auth_items_t items
, const char *key
, double value
)
1044 auth_item_t item
= _find_item(items
,key
);
1045 if (item
&& item
->type
== AI_TYPE_DOUBLE
) {
1046 *(double*)item
->data
.value
= value
;
1048 item
= auth_item_create(AI_TYPE_DOUBLE
, key
, &value
, sizeof(double), 0);
1050 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
1051 CFReleaseSafe(item
);
1056 double auth_items_get_double(auth_items_t items
, const char *key
)
1058 auth_item_t item
= _find_item(items
,key
);
1061 if (!(item
->type
==AI_TYPE_DOUBLE
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(double))) {
1062 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
1063 item
->data
.name
, item
->type
, AI_TYPE_DOUBLE
, item
->data
.valueLength
, sizeof(double));
1066 if (item
->type
== AI_TYPE_STRING
) {
1067 return atof(auth_item_get_string(item
));
1070 require(item
->data
.value
!= NULL
, done
);
1071 require(item
->data
.valueLength
== sizeof(double), done
);
1073 return *(double*)item
->data
.value
;
1080 uint32_t auth_items_get_type(auth_items_t items
, const char *key
)
1082 auth_item_t item
= _find_item(items
,key
);
1087 return AI_TYPE_UNKNOWN
;
1090 size_t auth_items_get_length(auth_items_t items
, const char *key
)
1092 auth_item_t item
= _find_item(items
,key
);
1094 return item
->data
.valueLength
;
1100 void auth_items_set_value(auth_items_t items
, const char *key
, uint32_t type
, uint32_t flags
, const void *value
, size_t len
)
1102 auth_item_t item
= auth_item_create(type
, key
, value
, len
, flags
);
1104 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
1105 CFReleaseSafe(item
);
1110 #pragma mark auth_rights_t
1112 struct _auth_rights_s
{
1113 __AUTH_BASE_STRUCT_HEADER__
;
1115 CFMutableArrayRef array
;
1119 _auth_rights_finalize(CFTypeRef value
)
1121 auth_rights_t rights
= (auth_rights_t
)value
;
1123 CFReleaseNull(rights
->array
);
1127 _auth_rights_equal(CFTypeRef value1
, CFTypeRef value2
)
1129 auth_rights_t rights1
= (auth_rights_t
)value1
;
1130 auth_rights_t rights2
= (auth_rights_t
)value2
;
1132 return CFEqual(rights1
->array
, rights2
->array
);
1136 _auth_rights_copy_description(CFTypeRef value
)
1138 auth_rights_t rights
= (auth_rights_t
)value
;
1139 return CFCopyDescription(rights
->array
);
1142 AUTH_TYPE_INSTANCE(auth_rights
,
1145 .finalize
= _auth_rights_finalize
,
1146 .equal
= _auth_rights_equal
,
1148 .copyFormattingDesc
= NULL
,
1149 .copyDebugDesc
= _auth_rights_copy_description
1152 static CFTypeID
auth_rights_get_type_id()
1154 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
1155 static dispatch_once_t onceToken
;
1157 dispatch_once(&onceToken
, ^{
1158 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_rights
);
1164 static auth_rights_t
1165 _auth_rights_create()
1167 auth_rights_t rights
= NULL
;
1169 rights
= (auth_rights_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights
), NULL
);
1170 require(rights
!= NULL
, done
);
1172 rights
->array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1179 auth_rights_create()
1181 auth_rights_t rights
= _auth_rights_create();
1182 require(rights
!= NULL
, done
);
1188 auth_rights_t
auth_rights_create_with_xpc(const xpc_object_t data
)
1190 auth_rights_t rights
= _auth_rights_create();
1191 require(rights
!= NULL
, done
);
1192 require(data
!= NULL
, done
);
1193 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
1195 xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
1197 auth_item_t item
= auth_item_create_with_xpc(value
);
1199 CFArrayAppendValue(rights
->array
, item
);
1200 CFReleaseSafe(item
);
1210 xpc_object_t
auth_rights_export_xpc(auth_rights_t rights
)
1212 xpc_object_t array
= xpc_array_create(NULL
, 0);
1214 CFIndex count
= CFArrayGetCount(rights
->array
);
1215 for (CFIndex i
= 0; i
< count
; i
++) {
1216 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1217 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
1218 xpc_array_append_value(array
, xpc_data
);
1219 xpc_release_safe(xpc_data
);
1226 _find_right_item(auth_rights_t rights
, const char * key
)
1228 auth_item_t item
= NULL
;
1229 CFStringRef lookup
= NULL
;
1230 require(key
!= NULL
, done
);
1232 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1233 require(lookup
!= NULL
, done
);
1235 CFIndex count
= CFArrayGetCount(rights
->array
);
1236 for (CFIndex i
= 0; i
< count
; i
++) {
1237 auth_item_t tmp
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1238 if (tmp
&& CFEqual(auth_item_get_cf_key(tmp
), lookup
)) {
1245 CFReleaseSafe(lookup
);
1249 void auth_rights_set_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1251 auth_item_t item
= _find_right_item(rights
,key
);
1253 item
->data
.flags
|= flags
;
1257 void auth_rights_clear_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1259 auth_item_t item
= _find_right_item(rights
,key
);
1261 item
->data
.flags
&= ~flags
;
1265 uint32_t auth_rights_get_flags(auth_rights_t rights
, const char *key
)
1267 auth_item_t item
= _find_right_item(rights
,key
);
1269 return item
->data
.flags
;
1275 bool auth_rights_check_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1277 uint32_t current
= auth_rights_get_flags(rights
,key
);
1278 return flags
? (current
& flags
) != 0 : current
== 0;
1281 size_t auth_rights_get_count(auth_rights_t rights
)
1283 return (size_t)CFArrayGetCount(rights
->array
);
1286 void auth_rights_add(auth_rights_t rights
, const char *key
)
1288 auth_item_t item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
1290 CFArrayAppendValue(rights
->array
, item
);
1291 CFReleaseSafe(item
);
1295 bool auth_rights_exist(auth_rights_t rights
, const char *key
)
1297 return (_find_right_item(rights
,key
) != NULL
);
1300 void auth_rights_remove(auth_rights_t rights
, const char *key
)
1302 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1303 CFIndex count
= CFArrayGetCount(rights
->array
);
1304 for (CFIndex i
= 0; i
< count
; i
++) {
1305 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1306 if (CFEqual(auth_item_get_cf_key(item
), lookup
)) {
1307 CFArrayRemoveValueAtIndex(rights
->array
, i
);
1312 CFReleaseSafe(lookup
);
1315 void auth_rights_clear(auth_rights_t rights
)
1317 CFArrayRemoveAllValues(rights
->array
);
1321 auth_rights_iterate(auth_rights_t rights
, bool(^iter
)(const char * key
))
1323 bool result
= false;
1325 CFIndex count
= CFArrayGetCount(rights
->array
);
1326 for (CFIndex i
= 0; i
< count
; i
++) {
1327 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1328 result
= iter(item
->data
.name
);