1 /* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */
7 #include "authutilities.h"
8 #include <Security/AuthorizationTags.h>
9 #include <dispatch/private.h>
11 typedef struct _auth_item_s
* auth_item_t
;
14 #pragma mark auth_item_t
17 __AUTH_BASE_STRUCT_HEADER__
;
19 AuthorizationItem data
;
27 auth_item_get_string(auth_item_t item
)
29 if (item
->bufLen
<= item
->data
.valueLength
) {
30 item
->bufLen
= item
->data
.valueLength
+1; // make sure buffer has a null char
31 item
->data
.value
= realloc(item
->data
.value
, item
->bufLen
);
32 if (item
->data
.value
== NULL
) {
33 // this is added to prevent running off into random memory if a string buffer doesn't have a null char
34 LOGE("realloc failed");
37 ((uint8_t*)item
->data
.value
)[item
->bufLen
-1] = '\0';
39 return item
->data
.value
;
43 auth_item_get_cf_key(auth_item_t item
)
46 item
->cfKey
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, item
->data
.name
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
51 static AuthorizationItem
*
52 auth_item_get_auth_item(auth_item_t item
)
58 auth_item_copy_auth_item_xpc(auth_item_t item
)
60 xpc_object_t xpc_data
= xpc_dictionary_create(NULL
, NULL
, 0);
61 xpc_dictionary_set_string(xpc_data
, AUTH_XPC_ITEM_NAME
, item
->data
.name
);
62 if (item
->data
.value
) {
63 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
64 bool sensitive
= strcmp(item
->data
.name
, "password") == 0;
66 vm_address_t vmBytes
= 0;
67 size_t xpcOutOfBandBlockSize
= (item
->data
.valueLength
> 32768 ? item
->data
.valueLength
: 32768); // min 16K on 64-bit systems and 12K on 32-bit systems
68 vm_allocate(mach_task_self(), &vmBytes
, xpcOutOfBandBlockSize
, VM_FLAGS_ANYWHERE
);
69 memcpy((void *)vmBytes
, item
->data
.value
, item
->data
.valueLength
);
70 dispatch_data_t dispData
= dispatch_data_create((void *)vmBytes
, xpcOutOfBandBlockSize
, DISPATCH_TARGET_QUEUE_DEFAULT
, DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE
); // out-of-band mapping
71 xpc_object_t xpcData
= xpc_data_create_with_dispatch_data(dispData
);
72 dispatch_release(dispData
);
73 xpc_dictionary_set_value(xpc_data
, AUTH_XPC_ITEM_VALUE
, xpcData
);
75 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
, item
->data
.valueLength
);
77 xpc_dictionary_set_data(xpc_data
, AUTH_XPC_ITEM_VALUE
, item
->data
.value
, item
->data
.valueLength
);
80 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_FLAGS
, item
->data
.flags
);
81 xpc_dictionary_set_uint64(xpc_data
, AUTH_XPC_ITEM_TYPE
, item
->type
);
86 _auth_item_finalize(CFTypeRef value
)
88 auth_item_t item
= (auth_item_t
)value
;
90 CFReleaseSafe(item
->cfKey
);
92 if (item
->data
.name
) {
93 free((void*)item
->data
.name
);
96 if (item
->data
.value
) {
97 memset(item
->data
.value
, 0, item
->data
.valueLength
);
98 free(item
->data
.value
);
103 _auth_item_equal(CFTypeRef value1
, CFTypeRef value2
)
105 return (CFHash(value1
) == CFHash(value2
));
109 _auth_item_copy_description(CFTypeRef value
)
112 auth_item_t item
= (auth_item_t
)value
;
115 static size_t passLen
= strlen(kAuthorizationEnvironmentPassword
);
116 if (strncasecmp(item
->data
.name
, kAuthorizationEnvironmentPassword
, passLen
) == 0) {
121 CFMutableStringRef desc
= CFStringCreateMutable(kCFAllocatorDefault
, 0);
122 CFStringAppendFormat(desc
, NULL
, CFSTR("auth_item: %s, type=%i, length=%li, flags=%x"),
123 item
->data
.name
, item
->type
,
124 hidden
? 0 : item
->data
.valueLength
, (unsigned int)item
->data
.flags
);
126 switch (item
->type
) {
128 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%s"), hidden
? "(hidden)" : auth_item_get_string(item
));
131 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(int32_t*)item
->data
.value
);
134 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%u"), *(uint32_t*)item
->data
.value
);
137 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%lli"), *(int64_t*)item
->data
.value
);
140 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%llu"), *(uint64_t*)item
->data
.value
);
143 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%i"), *(bool*)item
->data
.value
);
146 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=%f"), *(double*)item
->data
.value
);
149 case AI_TYPE_UNKNOWN
:
151 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=(hidden)"));
153 CFStringAppendFormat(desc
, NULL
, CFSTR(" value=0x"));
154 size_t i
= item
->data
.valueLength
< 10 ? item
->data
.valueLength
: 10;
155 uint8_t * data
= item
->data
.value
;
157 CFStringAppendFormat(desc
, NULL
, CFSTR("%02x"), data
[i
-1]);
168 _auth_item_hash(CFTypeRef value
)
170 auth_item_t item
= (auth_item_t
)value
;
171 uint64_t crc
= crc64_init();
172 crc
= crc64_update(crc
, item
->data
.name
, strlen(item
->data
.name
));
173 if (item
->data
.value
) {
174 crc
= crc64_update(crc
, item
->data
.value
, item
->data
.valueLength
);
176 crc
= crc64_update(crc
, &item
->data
.flags
, sizeof(item
->data
.flags
));
178 crc
= crc64_final(crc
);
179 return (CFHashCode
)crc
;
182 AUTH_TYPE_INSTANCE(auth_item
,
185 .finalize
= _auth_item_finalize
,
186 .equal
= _auth_item_equal
,
187 .hash
= _auth_item_hash
,
188 .copyFormattingDesc
= NULL
,
189 .copyDebugDesc
= _auth_item_copy_description
192 static CFTypeID
auth_item_get_type_id() {
193 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
194 static dispatch_once_t onceToken
;
196 dispatch_once(&onceToken
, ^{
197 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_item
);
206 auth_item_t item
= NULL
;
208 item
= (auth_item_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_item_get_type_id(), AUTH_CLASS_SIZE(auth_item
), NULL
);
209 require(item
!= NULL
, done
);
216 auth_item_create(uint32_t type
, const char * name
, const void * value
, size_t valueLen
, uint32_t flags
)
218 auth_item_t item
= NULL
;
219 require(name
!= NULL
, done
);
221 item
= _auth_item_create();
222 require(item
!= NULL
, done
);
225 item
->data
.flags
= flags
;
226 item
->data
.name
= _copy_string(name
);
227 item
->data
.valueLength
= valueLen
;
228 item
->bufLen
= valueLen
;
230 if (item
->type
== AI_TYPE_STRING
) {
232 item
->data
.value
= calloc(1u, item
->bufLen
);
233 } else if (valueLen
) {
234 item
->data
.value
= calloc(1u, item
->bufLen
);
237 memcpy(item
->data
.value
, value
, valueLen
);
246 auth_item_create_with_xpc(xpc_object_t data
)
248 auth_item_t item
= NULL
;
249 require(data
!= NULL
, done
);
250 require(xpc_get_type(data
) == XPC_TYPE_DICTIONARY
, done
);
251 require(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
) != NULL
, done
);
253 item
= _auth_item_create();
254 require(item
!= NULL
, done
);
256 item
->data
.name
= _copy_string(xpc_dictionary_get_string(data
, AUTH_XPC_ITEM_NAME
));
257 item
->data
.flags
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_FLAGS
);
258 item
->type
= (uint32_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_TYPE
);
261 const void * value
= xpc_dictionary_get_data(data
, AUTH_XPC_ITEM_VALUE
, &len
);
263 // <rdar://problem/13033889> authd is holding on to multiple copies of my password in the clear
264 bool sensitive
= xpc_dictionary_get_value(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
266 size_t sensitiveLength
= (size_t)xpc_dictionary_get_uint64(data
, AUTH_XPC_ITEM_SENSITIVE_VALUE_LENGTH
);
267 item
->bufLen
= sensitiveLength
;
268 item
->data
.valueLength
= sensitiveLength
;
269 item
->data
.value
= calloc(1u, sensitiveLength
);
270 memcpy(item
->data
.value
, value
, sensitiveLength
);
271 memset_s((void *)value
, len
, 0, sensitiveLength
); // clear the sensitive data, memset_s is never optimized away
274 item
->data
.valueLength
= len
;
275 item
->data
.value
= calloc(1u, len
);
276 memcpy(item
->data
.value
, value
, len
);
285 #pragma mark auth_items_t
287 struct _auth_items_s
{
288 __AUTH_BASE_STRUCT_HEADER__
;
290 CFMutableDictionaryRef dictionary
;
291 AuthorizationItemSet set
;
295 _auth_items_finalize(CFTypeRef value
)
297 auth_items_t items
= (auth_items_t
)value
;
299 CFReleaseNull(items
->dictionary
);
300 free_safe(items
->set
.items
)
304 _auth_items_equal(CFTypeRef value1
, CFTypeRef value2
)
306 auth_items_t items1
= (auth_items_t
)value1
;
307 auth_items_t items2
= (auth_items_t
)value2
;
309 return CFEqual(items1
->dictionary
, items2
->dictionary
);
313 _auth_items_copy_description(CFTypeRef value
)
315 auth_items_t items
= (auth_items_t
)value
;
316 return CFCopyDescription(items
->dictionary
);
319 AUTH_TYPE_INSTANCE(auth_items
,
322 .finalize
= _auth_items_finalize
,
323 .equal
= _auth_items_equal
,
325 .copyFormattingDesc
= NULL
,
326 .copyDebugDesc
= _auth_items_copy_description
329 CFTypeID
auth_items_get_type_id()
331 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
332 static dispatch_once_t onceToken
;
334 dispatch_once(&onceToken
, ^{
335 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_items
);
342 _auth_items_create(bool createDict
)
344 auth_items_t items
= NULL
;
346 items
= (auth_items_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_items_get_type_id(), AUTH_CLASS_SIZE(auth_items
), NULL
);
347 require(items
!= NULL
, done
);
350 items
->dictionary
= CFDictionaryCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
360 auth_items_t items
= NULL
;
362 items
= _auth_items_create(true);
363 require(items
!= NULL
, done
);
370 _auth_items_parse_xpc(auth_items_t items
, const xpc_object_t data
)
373 require(data
!= NULL
, done
);
374 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
376 result
= xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
378 auth_item_t item
= auth_item_create_with_xpc(value
);
380 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
391 auth_items_t
auth_items_create_with_xpc(const xpc_object_t data
)
393 auth_items_t items
= NULL
;
395 items
= _auth_items_create(true);
396 require(items
!= NULL
, done
);
398 _auth_items_parse_xpc(items
, data
);
405 auth_items_create_copy(auth_items_t copy
)
407 auth_items_t items
= NULL
;
409 items
= _auth_items_create(false);
410 require(items
!= NULL
, done
);
412 items
->dictionary
= CFDictionaryCreateMutableCopy(kCFAllocatorDefault
, CFDictionaryGetCount(copy
->dictionary
), copy
->dictionary
);
419 auth_items_get_count(auth_items_t items
)
421 return (size_t)CFDictionaryGetCount(items
->dictionary
);
424 AuthorizationItemSet
*
425 auth_items_get_item_set(auth_items_t items
)
427 uint32_t count
= (uint32_t)CFDictionaryGetCount(items
->dictionary
);
429 size_t size
= count
* sizeof(AuthorizationItem
);
430 if (items
->set
.items
== NULL
) {
431 items
->set
.items
= calloc(1u, size
);
432 require(items
->set
.items
!= NULL
, done
);
434 if (count
> items
->set
.count
) {
435 items
->set
.items
= realloc(items
->set
.items
, size
);
436 require_action(items
->set
.items
!= NULL
, done
, items
->set
.count
= 0);
439 items
->set
.count
= count
;
440 CFTypeRef keys
[count
], values
[count
];
441 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
442 for (uint32_t i
= 0; i
< count
; i
++) {
443 auth_item_t item
= (auth_item_t
)values
[i
];
444 items
->set
.items
[i
] = *auth_item_get_auth_item(item
);
447 items
->set
.count
= 0;
455 auth_items_export_xpc(auth_items_t items
)
457 xpc_object_t array
= xpc_array_create(NULL
, 0);
459 _cf_dictionary_iterate(items
->dictionary
, ^bool(CFTypeRef key AUTH_UNUSED
, CFTypeRef value
) {
460 auth_item_t item
= (auth_item_t
)value
;
461 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
462 xpc_array_append_value(array
, xpc_data
);
463 xpc_release_safe(xpc_data
);
471 _find_item(auth_items_t items
, const char * key
)
473 auth_item_t item
= NULL
;
474 CFStringRef lookup
= NULL
;
475 require(key
!= NULL
, done
);
477 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
478 require(lookup
!= NULL
, done
);
480 item
= (auth_item_t
)CFDictionaryGetValue(items
->dictionary
, lookup
);
483 CFReleaseSafe(lookup
);
488 auth_items_set_flags(auth_items_t items
, const char *key
, uint32_t flags
)
490 auth_item_t item
= _find_item(items
,key
);
492 item
->data
.flags
|= flags
;
497 auth_items_clear_flags(auth_items_t items
, const char *key
, uint32_t flags
)
499 auth_item_t item
= _find_item(items
,key
);
501 item
->data
.flags
&= ~flags
;
506 auth_items_get_flags(auth_items_t items
, const char *key
)
508 auth_item_t item
= _find_item(items
,key
);
510 return item
->data
.flags
;
517 auth_items_check_flags(auth_items_t items
, const char *key
, uint32_t flags
)
519 // When several bits are set in uint32_t flags, "(current & flags) != 0" checks if ANY flag is set, not all flags!
520 // This odd behavior is currently being relied upon in several places, so be careful when changing / fixing this.
521 // However, this also risks unwanted information leakage in
522 // AuthorizationCopyInfo ==> authorization_copy_info ==> [all info] auth_items_copy_with_flags
523 uint32_t current
= auth_items_get_flags(items
,key
);
524 return flags
? (current
& flags
) != 0 : current
== 0;
528 auth_items_set_key(auth_items_t items
, const char *key
)
530 auth_item_t item
= _find_item(items
,key
);
532 item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
534 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
541 auth_items_exist(auth_items_t items
, const char *key
)
543 return _find_item(items
,key
) != NULL
;
547 auth_items_remove(auth_items_t items
, const char *key
)
549 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
550 CFDictionaryRemoveValue(items
->dictionary
, lookup
);
551 CFReleaseSafe(lookup
);
555 auth_items_remove_with_flags(auth_items_t items
, uint32_t flags
)
557 auth_items_iterate(items
, ^bool(const char *key
) {
558 if (auth_items_check_flags(items
, key
, flags
)) {
559 auth_items_remove(items
,key
);
566 auth_items_clear(auth_items_t items
)
568 CFDictionaryRemoveAllValues(items
->dictionary
);
572 auth_items_copy(auth_items_t items
, auth_items_t src
)
574 auth_items_iterate(src
, ^bool(const char *key
) {
575 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
576 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
577 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
578 CFReleaseSafe(lookup
);
584 auth_items_copy_xpc(auth_items_t items
, const xpc_object_t src
)
586 _auth_items_parse_xpc(items
,src
);
590 auth_items_copy_with_flags(auth_items_t items
, auth_items_t src
, uint32_t flags
)
592 auth_items_iterate(src
, ^bool(const char *key
) {
593 if (auth_items_check_flags(src
, key
, flags
)) {
594 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
595 auth_item_t item
= (auth_item_t
)CFDictionaryGetValue(src
->dictionary
, lookup
);
596 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
597 CFReleaseSafe(lookup
);
604 auth_items_iterate(auth_items_t items
, auth_items_iterator_t iter
)
607 CFTypeRef
* keys
= NULL
;
608 CFTypeRef
* values
= NULL
;
610 CFIndex count
= CFDictionaryGetCount(items
->dictionary
);
611 keys
= calloc((size_t)count
, sizeof(CFTypeRef
));
612 require(keys
!= NULL
, done
);
614 values
= calloc((size_t)count
, sizeof(CFTypeRef
));
615 require(values
!= NULL
, done
);
617 CFDictionaryGetKeysAndValues(items
->dictionary
, keys
, values
);
618 for (CFIndex i
= 0; i
< count
; i
++) {
619 auth_item_t item
= (auth_item_t
)values
[i
];
620 result
= iter(item
->data
.name
);
633 auth_items_set_string(auth_items_t items
, const char *key
, const char *value
)
635 assert(value
); // marked non-null
637 size_t valLen
= strlen(value
);
638 auth_item_t item
= _find_item(items
,key
);
639 if (item
&& item
->type
== AI_TYPE_STRING
&& valLen
< item
->bufLen
) {
640 memcpy(item
->data
.value
, value
, valLen
+1); // copy null
641 item
->data
.valueLength
= valLen
;
643 item
= auth_item_create(AI_TYPE_STRING
, key
, value
, valLen
, 0);
645 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
652 auth_items_get_string(auth_items_t items
, const char *key
)
654 auth_item_t item
= _find_item(items
,key
);
657 if (!(item
->type
== AI_TYPE_STRING
|| item
->type
== AI_TYPE_UNKNOWN
)) {
658 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
659 item
->data
.name
, item
->type
, AI_TYPE_STRING
);
662 return auth_item_get_string(item
);
669 auth_items_set_data(auth_items_t items
, const char *key
, const void *value
, size_t len
)
671 assert(value
); // marked non-null
674 auth_item_t item
= _find_item(items
,key
);
675 if (item
&& item
->type
== AI_TYPE_DATA
&& len
<= item
->bufLen
) {
676 memcpy(item
->data
.value
, value
, len
);
677 item
->data
.valueLength
= len
;
679 item
= auth_item_create(AI_TYPE_DATA
, key
, value
, len
, 0);
681 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
689 auth_items_get_data(auth_items_t items
, const char *key
, size_t *len
)
691 assert(len
); // marked non-null
693 auth_item_t item
= _find_item(items
,key
);
696 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
697 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
698 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
701 *len
= item
->data
.valueLength
;
702 return item
->data
.value
;
709 auth_items_get_data_with_flags(auth_items_t items
, const char *key
, size_t *len
, uint32_t flags
)
711 assert(len
); // marked non-null
713 auth_item_t item
= _find_item(items
,key
);
714 if (item
&& (item
->data
.flags
& flags
) == flags
) {
716 if (!(item
->type
== AI_TYPE_DATA
|| item
->type
== AI_TYPE_UNKNOWN
)) {
717 LOGV("auth_items: key = %s, invalid type=%i expected=%i",
718 item
->data
.name
, item
->type
, AI_TYPE_DATA
);
721 *len
= item
->data
.valueLength
;
723 return item
->data
.value
;
730 auth_items_set_bool(auth_items_t items
, const char *key
, bool value
)
732 auth_item_t item
= _find_item(items
,key
);
733 if (item
&& item
->type
== AI_TYPE_BOOL
) {
734 *(bool*)item
->data
.value
= value
;
736 item
= auth_item_create(AI_TYPE_BOOL
, key
, &value
, sizeof(bool), 0);
738 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
745 auth_items_get_bool(auth_items_t items
, const char *key
)
747 auth_item_t item
= _find_item(items
,key
);
750 if (!(item
->type
== AI_TYPE_BOOL
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(bool))) {
751 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
752 item
->data
.name
, item
->type
, AI_TYPE_BOOL
, item
->data
.valueLength
, sizeof(bool));
755 if (item
->type
== AI_TYPE_STRING
) {
756 return atoi(auth_item_get_string(item
));
759 require(item
->data
.value
!= NULL
, done
);
760 require(item
->data
.valueLength
== sizeof(bool), done
);
762 return *(bool*)item
->data
.value
;
770 auth_items_set_int(auth_items_t items
, const char *key
, int32_t value
)
772 auth_item_t item
= _find_item(items
,key
);
773 if (item
&& item
->type
== AI_TYPE_INT
) {
774 *(int32_t*)item
->data
.value
= value
;
776 item
= auth_item_create(AI_TYPE_INT
, key
, &value
, sizeof(int32_t), 0);
778 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
785 auth_items_get_int(auth_items_t items
, const char *key
)
787 auth_item_t item
= _find_item(items
,key
);
790 if (!(item
->type
==AI_TYPE_INT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int32_t))) {
791 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
792 item
->data
.name
, item
->type
, AI_TYPE_INT
, item
->data
.valueLength
, sizeof(int32_t));
795 if (item
->type
== AI_TYPE_STRING
) {
796 return atoi(auth_item_get_string(item
));
799 require(item
->data
.value
!= NULL
, done
);
800 require(item
->data
.valueLength
== sizeof(int32_t), done
);
802 return *(int32_t*)item
->data
.value
;
810 auth_items_set_uint(auth_items_t items
, const char *key
, uint32_t value
)
812 auth_item_t item
= _find_item(items
,key
);
813 if (item
&& item
->type
== AI_TYPE_UINT
) {
814 *(uint32_t*)item
->data
.value
= value
;
816 item
= auth_item_create(AI_TYPE_UINT
, key
, &value
, sizeof(uint32_t), 0);
818 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
825 auth_items_get_uint(auth_items_t items
, const char *key
)
827 auth_item_t item
= _find_item(items
,key
);
830 if (!(item
->type
==AI_TYPE_UINT
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint32_t))) {
831 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
832 item
->data
.name
, item
->type
, AI_TYPE_UINT
, item
->data
.valueLength
, sizeof(uint32_t));
835 if (item
->type
== AI_TYPE_STRING
) {
836 return (uint32_t)atoi(auth_item_get_string(item
));
839 require(item
->data
.value
!= NULL
, done
);
840 require(item
->data
.valueLength
== sizeof(uint32_t), done
);
842 return *(uint32_t*)item
->data
.value
;
850 auth_items_set_int64(auth_items_t items
, const char *key
, int64_t value
)
852 auth_item_t item
= _find_item(items
,key
);
853 if (item
&& item
->type
== AI_TYPE_INT64
) {
854 *(int64_t*)item
->data
.value
= value
;
856 item
= auth_item_create(AI_TYPE_INT64
, key
, &value
, sizeof(int64_t), 0);
858 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
865 auth_items_get_int64(auth_items_t items
, const char *key
)
867 auth_item_t item
= _find_item(items
,key
);
870 if (!(item
->type
==AI_TYPE_INT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(int64_t))) {
871 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
872 item
->data
.name
, item
->type
, AI_TYPE_INT64
, item
->data
.valueLength
, sizeof(int64_t));
875 if (item
->type
== AI_TYPE_STRING
) {
876 return atoll(auth_item_get_string(item
));
879 require(item
->data
.value
!= NULL
, done
);
880 require(item
->data
.valueLength
== sizeof(int64_t), done
);
882 return *(int64_t*)item
->data
.value
;
890 auth_items_set_uint64(auth_items_t items
, const char *key
, uint64_t value
)
892 auth_item_t item
= _find_item(items
,key
);
893 if (item
&& item
->type
== AI_TYPE_UINT64
) {
894 *(uint64_t*)item
->data
.value
= value
;
896 item
= auth_item_create(AI_TYPE_UINT64
, key
, &value
, sizeof(uint64_t), 0);
898 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
905 auth_items_get_uint64(auth_items_t items
, const char *key
)
907 auth_item_t item
= _find_item(items
,key
);
910 if (!(item
->type
==AI_TYPE_UINT64
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(uint64_t))) {
911 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
912 item
->data
.name
, item
->type
, AI_TYPE_UINT64
, item
->data
.valueLength
, sizeof(uint64_t));
915 if (item
->type
== AI_TYPE_STRING
) {
916 return (uint64_t)atoll(auth_item_get_string(item
));
919 require(item
->data
.value
!= NULL
, done
);
920 require(item
->data
.valueLength
== sizeof(uint64_t), done
);
922 return *(uint64_t*)item
->data
.value
;
929 void auth_items_set_double(auth_items_t items
, const char *key
, double value
)
931 auth_item_t item
= _find_item(items
,key
);
932 if (item
&& item
->type
== AI_TYPE_DOUBLE
) {
933 *(double*)item
->data
.value
= value
;
935 item
= auth_item_create(AI_TYPE_DOUBLE
, key
, &value
, sizeof(double), 0);
937 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
943 double auth_items_get_double(auth_items_t items
, const char *key
)
945 auth_item_t item
= _find_item(items
,key
);
948 if (!(item
->type
==AI_TYPE_DOUBLE
|| item
->type
== AI_TYPE_UNKNOWN
) || (item
->data
.valueLength
!= sizeof(double))) {
949 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li",
950 item
->data
.name
, item
->type
, AI_TYPE_DOUBLE
, item
->data
.valueLength
, sizeof(double));
953 if (item
->type
== AI_TYPE_STRING
) {
954 return atof(auth_item_get_string(item
));
957 require(item
->data
.value
!= NULL
, done
);
958 require(item
->data
.valueLength
== sizeof(double), done
);
960 return *(double*)item
->data
.value
;
967 uint32_t auth_items_get_type(auth_items_t items
, const char *key
)
969 auth_item_t item
= _find_item(items
,key
);
974 return AI_TYPE_UNKNOWN
;
977 size_t auth_items_get_length(auth_items_t items
, const char *key
)
979 auth_item_t item
= _find_item(items
,key
);
981 return item
->data
.valueLength
;
987 void auth_items_set_value(auth_items_t items
, const char *key
, uint32_t type
, uint32_t flags
, const void *value
, size_t len
)
989 auth_item_t item
= auth_item_create(type
, key
, value
, len
, flags
);
991 CFDictionarySetValue(items
->dictionary
, auth_item_get_cf_key(item
), item
);
997 #pragma mark auth_rights_t
999 struct _auth_rights_s
{
1000 __AUTH_BASE_STRUCT_HEADER__
;
1002 CFMutableArrayRef array
;
1006 _auth_rights_finalize(CFTypeRef value
)
1008 auth_rights_t rights
= (auth_rights_t
)value
;
1010 CFReleaseNull(rights
->array
);
1014 _auth_rights_equal(CFTypeRef value1
, CFTypeRef value2
)
1016 auth_rights_t rights1
= (auth_rights_t
)value1
;
1017 auth_rights_t rights2
= (auth_rights_t
)value2
;
1019 return CFEqual(rights1
->array
, rights2
->array
);
1023 _auth_rights_copy_description(CFTypeRef value
)
1025 auth_rights_t rights
= (auth_rights_t
)value
;
1026 return CFCopyDescription(rights
->array
);
1029 AUTH_TYPE_INSTANCE(auth_rights
,
1032 .finalize
= _auth_rights_finalize
,
1033 .equal
= _auth_rights_equal
,
1035 .copyFormattingDesc
= NULL
,
1036 .copyDebugDesc
= _auth_rights_copy_description
1039 static CFTypeID
auth_rights_get_type_id()
1041 static CFTypeID type_id
= _kCFRuntimeNotATypeID
;
1042 static dispatch_once_t onceToken
;
1044 dispatch_once(&onceToken
, ^{
1045 type_id
= _CFRuntimeRegisterClass(&_auth_type_auth_rights
);
1051 static auth_rights_t
1052 _auth_rights_create()
1054 auth_rights_t rights
= NULL
;
1056 rights
= (auth_rights_t
)_CFRuntimeCreateInstance(kCFAllocatorDefault
, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights
), NULL
);
1057 require(rights
!= NULL
, done
);
1059 rights
->array
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &kCFTypeArrayCallBacks
);
1066 auth_rights_create()
1068 auth_rights_t rights
= _auth_rights_create();
1069 require(rights
!= NULL
, done
);
1075 auth_rights_t
auth_rights_create_with_xpc(const xpc_object_t data
)
1077 auth_rights_t rights
= _auth_rights_create();
1078 require(rights
!= NULL
, done
);
1079 require(data
!= NULL
, done
);
1080 require(xpc_get_type(data
) == XPC_TYPE_ARRAY
, done
);
1082 xpc_array_apply(data
, ^bool(size_t index AUTH_UNUSED
, xpc_object_t value
) {
1084 auth_item_t item
= auth_item_create_with_xpc(value
);
1086 CFArrayAppendValue(rights
->array
, item
);
1087 CFReleaseSafe(item
);
1097 xpc_object_t
auth_rights_export_xpc(auth_rights_t rights
)
1099 xpc_object_t array
= xpc_array_create(NULL
, 0);
1101 CFIndex count
= CFArrayGetCount(rights
->array
);
1102 for (CFIndex i
= 0; i
< count
; i
++) {
1103 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1104 xpc_object_t xpc_data
= auth_item_copy_auth_item_xpc(item
);
1105 xpc_array_append_value(array
, xpc_data
);
1106 xpc_release_safe(xpc_data
);
1113 _find_right_item(auth_rights_t rights
, const char * key
)
1115 auth_item_t item
= NULL
;
1116 CFStringRef lookup
= NULL
;
1117 require(key
!= NULL
, done
);
1119 lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1120 require(lookup
!= NULL
, done
);
1122 CFIndex count
= CFArrayGetCount(rights
->array
);
1123 for (CFIndex i
= 0; i
< count
; i
++) {
1124 auth_item_t tmp
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1125 if (tmp
&& CFEqual(auth_item_get_cf_key(tmp
), lookup
)) {
1132 CFReleaseSafe(lookup
);
1136 void auth_rights_set_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1138 auth_item_t item
= _find_right_item(rights
,key
);
1140 item
->data
.flags
|= flags
;
1144 void auth_rights_clear_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1146 auth_item_t item
= _find_right_item(rights
,key
);
1148 item
->data
.flags
&= ~flags
;
1152 uint32_t auth_rights_get_flags(auth_rights_t rights
, const char *key
)
1154 auth_item_t item
= _find_right_item(rights
,key
);
1156 return item
->data
.flags
;
1162 bool auth_rights_check_flags(auth_rights_t rights
, const char *key
, uint32_t flags
)
1164 uint32_t current
= auth_rights_get_flags(rights
,key
);
1165 return flags
? (current
& flags
) != 0 : current
== 0;
1168 size_t auth_rights_get_count(auth_rights_t rights
)
1170 return (size_t)CFArrayGetCount(rights
->array
);
1173 void auth_rights_add(auth_rights_t rights
, const char *key
)
1175 auth_item_t item
= auth_item_create(AI_TYPE_RIGHT
, key
, NULL
, 0, 0);
1177 CFArrayAppendValue(rights
->array
, item
);
1178 CFReleaseSafe(item
);
1182 bool auth_rights_exist(auth_rights_t rights
, const char *key
)
1184 return (_find_right_item(rights
,key
) != NULL
);
1187 void auth_rights_remove(auth_rights_t rights
, const char *key
)
1189 CFStringRef lookup
= CFStringCreateWithCStringNoCopy(kCFAllocatorDefault
, key
, kCFStringEncodingUTF8
, kCFAllocatorNull
);
1190 CFIndex count
= CFArrayGetCount(rights
->array
);
1191 for (CFIndex i
= 0; i
< count
; i
++) {
1192 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1193 if (CFEqual(auth_item_get_cf_key(item
), lookup
)) {
1194 CFArrayRemoveValueAtIndex(rights
->array
, i
);
1199 CFReleaseSafe(lookup
);
1202 void auth_rights_clear(auth_rights_t rights
)
1204 CFArrayRemoveAllValues(rights
->array
);
1208 auth_rights_iterate(auth_rights_t rights
, bool(^iter
)(const char * key
))
1210 bool result
= false;
1212 CFIndex count
= CFArrayGetCount(rights
->array
);
1213 for (CFIndex i
= 0; i
< count
; i
++) {
1214 auth_item_t item
= (auth_item_t
)CFArrayGetValueAtIndex(rights
->array
, i
);
1215 result
= iter(item
->data
.name
);