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
) {
652 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
653 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
654 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
655 CFReleaseSafe(lookup
);
661 auth_items_content_copy(auth_items_t items
, auth_items_t src
)
663 auth_items_iterate(src
, ^bool(const char *key
) {
664 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
665 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
666 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
668 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(new_item
), new_item
);
669 CFReleaseSafe(lookup
);
670 CFReleaseSafe(new_item
);
676 auth_items_copy_xpc(auth_items_t items
, const xpc_object_t src
)
678 _auth_items_parse_xpc(items
,src
);
682 auth_items_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
684 auth_items_iterate(src
, ^bool(const char *key
) {
685 if (auth_items_check_flags(src
, key
, flags
)) {
686 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
687 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
688 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
689 CFReleaseSafe(lookup
);
695 // unlike previous method, this one creates true new copy including their content
697 auth_items_content_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
699 auth_items_iterate(src
, ^bool(const char *key
) {
700 if (auth_items_check_flags(src
, key
, flags
)) {
701 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
702 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
703 auth_item_t new_item
= auth_item_create(item
->type
, item
->data
.name
, item
->data
.value
, item
->data
.valueLength
, item
->data
.flags
);
705 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(new_item
), new_item
);
706 CFReleaseSafe(lookup
);
707 CFReleaseSafe(new_item
);
714 auth_items_iterate(auth_items_t items
, auth_items_iterator_t iter
)
717 CFTypeRef
* keys
= NULL
;
718 CFTypeRef
* values
= NULL
;
720 CFIndex count
= CFDictionaryGetCount(items
->dictionary
);
721 keys
= calloc((size_t)count
, sizeof(CFTypeRef
));
722 require(keys
!= NULL
, done
);
724 values
= calloc((size_t)count
, sizeof(CFTypeRef
));
725 require(values
!= NULL
, done
);
727 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
728 for (CFIndex i
= 0; i
< count
; i
++) {
729 auth_item_t item
= (auth_item_t
)values
[i
];
730 result
= iter(item
->data
.name
);
743 auth_items_set_string(auth_items_t items
, const char *key
, const char *value
)
745 assert(value
); // marked non-null
747 size_t valLen
= strlen(value
);
748 auth_item_t item
= _find_item(items
,key
);
749 if (item
&& item
->type
== AI_TYPE_STRING
&& valLen
< item
->bufLen
) {
750 memcpy(item
->data
.value
, value
, valLen
+1); // copy null
751 item
->data
.valueLength
= valLen
;
753 item
= auth_item_create(AI_TYPE_STRING
, key
, value
, valLen
, 0);
755 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
762 auth_items_get_string(auth_items_t items
, const char *key
)
764 auth_item_t item
= _find_item(items
,key
);
767 if (!(item
->type
== AI_TYPE_STRING
|| item
->type
== AI_TYPE_UNKNOWN
)) {
768 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
769 item
->data
.name
, item
->type
, AI_TYPE_STRING
);
772 return auth_item_get_string(item
);
779 auth_items_set_data(auth_items_t items
, const char *key
, const void *value
, size_t len
)
781 assert(value
); // marked non-null
784 auth_item_t item
= _find_item(items
,key
);
785 if (item
&& item
->type
== AI_TYPE_DATA
&& len
<= item
->bufLen
) {
786 memcpy(item
->data
.value
, value
, len
);
787 item
->data
.valueLength
= len
;
789 item
= auth_item_create(AI_TYPE_DATA
, key
, value
, len
, 0);
791 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
799 auth_items_get_data(auth_items_t items
, const char *key
, size_t *len
)
801 assert(len
); // marked non-null
803 auth_item_t item
= _find_item(items
,key
);
806 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
807 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
808 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
811 *len
= item
->data
.valueLength
;
812 return item
->data
.value
;
819 auth_items_get_data_with_flags(auth_items_t items
, const char *key
, size_t *len
, uint32_t flags
)
821 assert(len
); // marked non-null
823 auth_item_t item
= _find_item(items
,key
);
824 if (item
&& (item
->data
.flags
& flags
) == flags
) {
826 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
827 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i",
828 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
831 *len
= item
->data
.valueLength
;
833 return item
->data
.value
;
840 auth_items_set_bool(auth_items_t items
, const char *key
, bool value
)
842 auth_item_t item
= _find_item(items
,key
);
843 if (item
&& item
->type
== AI_TYPE_BOOL
) {
844 *(bool*)item
->data
.value
= value
;
846 item
= auth_item_create(AI_TYPE_BOOL
, key
, &value
, sizeof(bool), 0);
848 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
855 auth_items_get_bool(auth_items_t items
, const char *key
)
857 auth_item_t item
= _find_item(items
,key
);
860 if (!(item
->type
== AI_TYPE_BOOL
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(bool))) {
861 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
862 item
->data
.name
, item
->type
, AI_TYPE_BOOL
, item
->data
.valueLength
, sizeof(bool));
865 if (item
->type
== AI_TYPE_STRING
) {
866 return atoi(auth_item_get_string(item
));
869 require(item
->data
.value
!= NULL
, done
);
870 require(item
->data
.valueLength
== sizeof(bool), done
);
872 return *(bool*)item
->data
.value
;
880 auth_items_set_int(auth_items_t items
, const char *key
, int32_t value
)
882 auth_item_t item
= _find_item(items
,key
);
883 if (item
&& item
->type
== AI_TYPE_INT
) {
884 *(int32_t*)item
->data
.value
= value
;
886 item
= auth_item_create(AI_TYPE_INT
, key
, &value
, sizeof(int32_t), 0);
888 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
895 auth_items_get_int(auth_items_t items
, const char *key
)
897 auth_item_t item
= _find_item(items
,key
);
900 if (!(item
->type
==AI_TYPE_INT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int32_t))) {
901 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
902 item
->data
.name
, item
->type
, AI_TYPE_INT
, item
->data
.valueLength
, sizeof(int32_t));
905 if (item
->type
== AI_TYPE_STRING
) {
906 return atoi(auth_item_get_string(item
));
909 require(item
->data
.value
!= NULL
, done
);
910 require(item
->data
.valueLength
== sizeof(int32_t), done
);
912 return *(int32_t*)item
->data
.value
;
920 auth_items_set_uint(auth_items_t items
, const char *key
, uint32_t value
)
922 auth_item_t item
= _find_item(items
,key
);
923 if (item
&& item
->type
== AI_TYPE_UINT
) {
924 *(uint32_t*)item
->data
.value
= value
;
926 item
= auth_item_create(AI_TYPE_UINT
, key
, &value
, sizeof(uint32_t), 0);
928 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
935 auth_items_get_uint(auth_items_t items
, const char *key
)
937 auth_item_t item
= _find_item(items
,key
);
940 if (!(item
->type
==AI_TYPE_UINT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint32_t))) {
941 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
942 item
->data
.name
, item
->type
, AI_TYPE_UINT
, item
->data
.valueLength
, sizeof(uint32_t));
945 if (item
->type
== AI_TYPE_STRING
) {
946 return (uint32_t)atoi(auth_item_get_string(item
));
949 require(item
->data
.value
!= NULL
, done
);
950 require(item
->data
.valueLength
== sizeof(uint32_t), done
);
952 return *(uint32_t*)item
->data
.value
;
960 auth_items_set_int64(auth_items_t items
, const char *key
, int64_t value
)
962 auth_item_t item
= _find_item(items
,key
);
963 if (item
&& item
->type
== AI_TYPE_INT64
) {
964 *(int64_t*)item
->data
.value
= value
;
966 item
= auth_item_create(AI_TYPE_INT64
, key
, &value
, sizeof(int64_t), 0);
968 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
975 auth_items_get_int64(auth_items_t items
, const char *key
)
977 auth_item_t item
= _find_item(items
,key
);
980 if (!(item
->type
==AI_TYPE_INT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int64_t))) {
981 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
982 item
->data
.name
, item
->type
, AI_TYPE_INT64
, item
->data
.valueLength
, sizeof(int64_t));
985 if (item
->type
== AI_TYPE_STRING
) {
986 return atoll(auth_item_get_string(item
));
989 require(item
->data
.value
!= NULL
, done
);
990 require(item
->data
.valueLength
== sizeof(int64_t), done
);
992 return *(int64_t*)item
->data
.value
;
1000 auth_items_set_uint64(auth_items_t items
, const char *key
, uint64_t value
)
1002 auth_item_t item
= _find_item(items
,key
);
1003 if (item
&& item
->type
== AI_TYPE_UINT64
) {
1004 *(uint64_t*)item
->data
.value
= value
;
1006 item
= auth_item_create(AI_TYPE_UINT64
, key
, &value
, sizeof(uint64_t), 0);
1008 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
1009 CFReleaseSafe(item
);
1015 auth_items_get_uint64(auth_items_t items
, const char *key
)
1017 auth_item_t item
= _find_item(items
,key
);
1020 if (!(item
->type
==AI_TYPE_UINT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint64_t))) {
1021 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
1022 item
->data
.name
, item
->type
, AI_TYPE_UINT64
, item
->data
.valueLength
, sizeof(uint64_t));
1025 if (item
->type
== AI_TYPE_STRING
) {
1026 return (uint64_t)atoll(auth_item_get_string(item
));
1029 require(item
->data
.value
!= NULL
, done
);
1030 require(item
->data
.valueLength
== sizeof(uint64_t), done
);
1032 return *(uint64_t*)item
->data
.value
;
1039 void auth_items_set_double(auth_items_t items
, const char *key
, double value
)
1041 auth_item_t item
= _find_item(items
,key
);
1042 if (item
&& item
->type
== AI_TYPE_DOUBLE
) {
1043 *(double*)item
->data
.value
= value
;
1045 item
= auth_item_create(AI_TYPE_DOUBLE
, key
, &value
, sizeof(double), 0);
1047 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
1048 CFReleaseSafe(item
);
1053 double auth_items_get_double(auth_items_t items
, const char *key
)
1055 auth_item_t item
= _find_item(items
,key
);
1058 if (!(item
->type
==AI_TYPE_DOUBLE
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(double))) {
1059 os_log_debug(AUTHD_LOG
, "items: key = %{public}s, invalid type=%i expected=%i or size=%li expected=%li",
1060 item
->data
.name
, item
->type
, AI_TYPE_DOUBLE
, item
->data
.valueLength
, sizeof(double));
1063 if (item
->type
== AI_TYPE_STRING
) {
1064 return atof(auth_item_get_string(item
));
1067 require(item
->data
.value
!= NULL
, done
);
1068 require(item
->data
.valueLength
== sizeof(double), done
);
1070 return *(double*)item
->data
.value
;
1077 uint32_t auth_items_get_type(auth_items_t items
, const char *key
)
1079 auth_item_t item
= _find_item(items
,key
);
1084 return AI_TYPE_UNKNOWN
;
1087 size_t auth_items_get_length(auth_items_t items
, const char *key
)
1089 auth_item_t item
= _find_item(items
,key
);
1091 return item
->data
.valueLength
;
1097 void auth_items_set_value(auth_items_t items
, const char *key
, uint32_t type
, uint32_t flags
, const void *value
, size_t len
)
1099 auth_item_t item
= auth_item_create(type
, key
, value
, len
, flags
);
1101 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
1102 CFReleaseSafe(item
);
1107 #pragma mark auth_rights_t
1109 struct _auth_rights_s
{
1110 __AUTH_BASE_STRUCT_HEADER__
;
1112 CFMutableArrayRef array
;
1116 _auth_rights_finalize(CFTypeRef value
)
1118 auth_rights_t rights
= (auth_rights_t
)value
;
1120 CFReleaseNull(rights
->array
);
1124 _auth_rights_equal(CFTypeRef value1
, CFTypeRef value2
)
1126 auth_rights_t rights1
= (auth_rights_t
)value1
;
1127 auth_rights_t rights2
= (auth_rights_t
)value2
;
1129 return CFEqual(rights1
->array
, rights2
->array
);
1133 _auth_rights_copy_description(CFTypeRef value
)
1135 auth_rights_t rights
= (auth_rights_t
)value
;
1136 return CFCopyDescription(rights
->array
);
1139 AUTH_TYPE_INSTANCE(auth_rights
,
1142 .finalize
= _auth_rights_finalize
,
1143 .equal
= _auth_rights_equal
,
1145 .copyFormattingDesc
= NULL
,
1146 .copyDebugDesc
= _auth_rights_copy_description
1149 static CFTypeID
auth_rights_get_type_id()
1151 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
1152 static dispatch_once_t onceToken
;
1154 dispatch_once(&onceToken
, ^{
1155 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_rights
);
1161 static auth_rights_t
1162 _auth_rights_create()
1164 auth_rights_t rights
= NULL
;
1166 rights
= (auth_rights_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights
), NULL
);
1167 require(rights
!= NULL
, done
);
1169 rights
->array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1176 auth_rights_create()
1178 auth_rights_t rights
= _auth_rights_create();
1179 require(rights
!= NULL
, done
);
1185 auth_rights_t
auth_rights_create_with_xpc(const xpc_object_t data
)
1187 auth_rights_t rights
= _auth_rights_create();
1188 require(rights
!= NULL
, done
);
1189 require(data
!= NULL
, done
);
1190 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
1192 xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
1194 auth_item_t item
= auth_item_create_with_xpc(value
);
1196 CFArrayAppendValue(rights
->array
, item
);
1197 CFReleaseSafe(item
);
1207 xpc_object_t
auth_rights_export_xpc(auth_rights_t rights
)
1209 xpc_object_t array
= xpc_array_create(NULL
, 0);
1211 CFIndex count
= CFArrayGetCount(rights
->array
);
1212 for (CFIndex i
= 0; i
< count
; i
++) {
1213 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1214 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
1215 xpc_array_append_value(array
, xpc_data
);
1216 xpc_release_safe(xpc_data
);
1223 _find_right_item(auth_rights_t rights
, const char * key
)
1225 auth_item_t item
= NULL
;
1226 CFStringRef lookup
= NULL
;
1227 require(key
!= NULL
, done
);
1229 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1230 require(lookup
!= NULL
, done
);
1232 CFIndex count
= CFArrayGetCount(rights
->array
);
1233 for (CFIndex i
= 0; i
< count
; i
++) {
1234 auth_item_t tmp
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1235 if (tmp
&& CFEqual(auth_item_get_cf_key(tmp
), lookup
)) {
1242 CFReleaseSafe(lookup
);
1246 void auth_rights_set_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1248 auth_item_t item
= _find_right_item(rights
,key
);
1250 item
->data
.flags
|= flags
;
1254 void auth_rights_clear_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1256 auth_item_t item
= _find_right_item(rights
,key
);
1258 item
->data
.flags
&= ~flags
;
1262 uint32_t auth_rights_get_flags(auth_rights_t rights
, const char *key
)
1264 auth_item_t item
= _find_right_item(rights
,key
);
1266 return item
->data
.flags
;
1272 bool auth_rights_check_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1274 uint32_t current
= auth_rights_get_flags(rights
,key
);
1275 return flags
? (current
& flags
) != 0 : current
== 0;
1278 size_t auth_rights_get_count(auth_rights_t rights
)
1280 return (size_t)CFArrayGetCount(rights
->array
);
1283 void auth_rights_add(auth_rights_t rights
, const char *key
)
1285 auth_item_t item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
1287 CFArrayAppendValue(rights
->array
, item
);
1288 CFReleaseSafe(item
);
1292 bool auth_rights_exist(auth_rights_t rights
, const char *key
)
1294 return (_find_right_item(rights
,key
) != NULL
);
1297 void auth_rights_remove(auth_rights_t rights
, const char *key
)
1299 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1300 CFIndex count
= CFArrayGetCount(rights
->array
);
1301 for (CFIndex i
= 0; i
< count
; i
++) {
1302 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1303 if (CFEqual(auth_item_get_cf_key(item
), lookup
)) {
1304 CFArrayRemoveValueAtIndex(rights
->array
, i
);
1309 CFReleaseSafe(lookup
);
1312 void auth_rights_clear(auth_rights_t rights
)
1314 CFArrayRemoveAllValues(rights
->array
);
1318 auth_rights_iterate(auth_rights_t rights
, bool(^iter
)(const char * key
))
1320 bool result
= false;
1322 CFIndex count
= CFArrayGetCount(rights
->array
);
1323 for (CFIndex i
= 0; i
< count
; i
++) {
1324 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1325 result
= iter(item
->data
.name
);