1/* Copyright (c) 2012-2013 Apple Inc. All Rights Reserved. */ 2 3#include "authitems.h" 4#include "crc.h" 5#include "debugging.h" 6 7#include "authutilities.h" 8#include <Security/AuthorizationTags.h> 9 10typedef struct _auth_item_s * auth_item_t; 11 12#pragma mark - 13#pragma mark auth_item_t 14 15struct _auth_item_s { 16 __AUTH_BASE_STRUCT_HEADER__; 17 18 AuthorizationItem data; 19 uint32_t type; 20 size_t bufLen; 21 22 CFStringRef cfKey; 23}; 24 25static const char * 26auth_item_get_string(auth_item_t item) 27{ 28 if (item->bufLen <= item->data.valueLength) { 29 item->bufLen = item->data.valueLength+1; // make sure buffer has a null char 30 item->data.value = realloc(item->data.value, item->bufLen); 31 if (item->data.value == NULL) { 32 // this is added to prevent running off into random memory if a string buffer doesn't have a null char 33 LOGE("realloc failed"); 34 abort(); 35 } 36 ((uint8_t*)item->data.value)[item->bufLen-1] = '\0'; 37 } 38 return item->data.value; 39} 40 41static CFStringRef 42auth_item_get_cf_key(auth_item_t item) 43{ 44 if (!item->cfKey) { 45 item->cfKey = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, item->data.name, kCFStringEncodingUTF8, kCFAllocatorNull); 46 } 47 return item->cfKey; 48} 49 50static AuthorizationItem * 51auth_item_get_auth_item(auth_item_t item) 52{ 53 return &item->data; 54} 55 56static xpc_object_t 57auth_item_copy_auth_item_xpc(auth_item_t item) 58{ 59 xpc_object_t xpc_data = xpc_dictionary_create(NULL, NULL, 0); 60 xpc_dictionary_set_string(xpc_data, AUTH_XPC_ITEM_NAME, item->data.name); 61 if (item->data.value) { 62 xpc_dictionary_set_data(xpc_data, AUTH_XPC_ITEM_VALUE, item->data.value, item->data.valueLength); 63 } 64 xpc_dictionary_set_uint64(xpc_data, AUTH_XPC_ITEM_FLAGS, item->data.flags); 65 xpc_dictionary_set_uint64(xpc_data, AUTH_XPC_ITEM_TYPE, item->type); 66 return xpc_data; 67} 68 69static void 70_auth_item_finalize(CFTypeRef value) 71{ 72 auth_item_t item = (auth_item_t)value; 73 74 CFReleaseSafe(item->cfKey); 75 76 if (item->data.name) { 77 free((void*)item->data.name); 78 } 79 80 if (item->data.value) { 81 memset(item->data.value, 0, item->data.valueLength); 82 free(item->data.value); 83 } 84} 85 86static Boolean 87_auth_item_equal(CFTypeRef value1, CFTypeRef value2) 88{ 89 return (CFHash(value1) == CFHash(value2)); 90} 91 92static CFStringRef 93_auth_item_copy_description(CFTypeRef value) 94{ 95 bool hidden = false; 96 auth_item_t item = (auth_item_t)value; 97 98#ifndef DEBUG 99 static size_t passLen = strlen(kAuthorizationEnvironmentPassword); 100 if (strncasecmp(item->data.name, kAuthorizationEnvironmentPassword, passLen) == 0) { 101 hidden = true; 102 } 103#endif 104 105 CFMutableStringRef desc = CFStringCreateMutable(kCFAllocatorDefault, 0); 106 CFStringAppendFormat(desc, NULL, CFSTR("auth_item: %s, type=%i, length=%li, flags=%x"), 107 item->data.name, item->type, 108 hidden ? 0 : item->data.valueLength, item->data.flags); 109 110 switch (item->type) { 111 case AI_TYPE_STRING: 112 CFStringAppendFormat(desc, NULL, CFSTR(" value=%s"), hidden ? "(hidden)" : auth_item_get_string(item)); 113 break; 114 case AI_TYPE_INT: 115 CFStringAppendFormat(desc, NULL, CFSTR(" value=%i"), *(int32_t*)item->data.value); 116 break; 117 case AI_TYPE_UINT: 118 CFStringAppendFormat(desc, NULL, CFSTR(" value=%u"), *(uint32_t*)item->data.value); 119 break; 120 case AI_TYPE_INT64: 121 CFStringAppendFormat(desc, NULL, CFSTR(" value=%lli"), *(int64_t*)item->data.value); 122 break; 123 case AI_TYPE_UINT64: 124 CFStringAppendFormat(desc, NULL, CFSTR(" value=%llu"), *(uint64_t*)item->data.value); 125 break; 126 case AI_TYPE_BOOL: 127 CFStringAppendFormat(desc, NULL, CFSTR(" value=%i"), *(bool*)item->data.value); 128 break; 129 case AI_TYPE_DOUBLE: 130 CFStringAppendFormat(desc, NULL, CFSTR(" value=%f"), *(double*)item->data.value); 131 break; 132 case AI_TYPE_DATA: 133 case AI_TYPE_UNKNOWN: 134 if (hidden) { 135 CFStringAppendFormat(desc, NULL, CFSTR(" value=(hidden)")); 136 } else { 137 CFStringAppendFormat(desc, NULL, CFSTR(" value=0x")); 138 size_t i = item->data.valueLength < 10 ? item->data.valueLength : 10; 139 uint8_t * data = item->data.value; 140 for (; i > 0; i--) { 141 CFStringAppendFormat(desc, NULL, CFSTR("%02x"), data[i-1]); 142 } 143 } 144 break; 145 default: 146 break; 147 } 148 return desc; 149} 150 151static CFHashCode 152_auth_item_hash(CFTypeRef value) 153{ 154 auth_item_t item = (auth_item_t)value; 155 uint64_t crc = crc64_init(); 156 crc = crc64_update(crc, item->data.name, strlen(item->data.name)); 157 if (item->data.value) { 158 crc = crc64_update(crc, item->data.value, item->data.valueLength); 159 } 160 crc = crc64_update(crc, &item->data.flags, sizeof(item->data.flags)); 161 162 crc = crc64_final(crc); 163 return crc; 164} 165 166AUTH_TYPE_INSTANCE(auth_item, 167 .init = NULL, 168 .copy = NULL, 169 .finalize = _auth_item_finalize, 170 .equal = _auth_item_equal, 171 .hash = _auth_item_hash, 172 .copyFormattingDesc = NULL, 173 .copyDebugDesc = _auth_item_copy_description 174 ); 175 176static CFTypeID auth_item_get_type_id() { 177 static CFTypeID type_id = _kCFRuntimeNotATypeID; 178 static dispatch_once_t onceToken; 179 180 dispatch_once(&onceToken, ^{ 181 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_item); 182 }); 183 184 return type_id; 185} 186 187static auth_item_t 188_auth_item_create() 189{ 190 auth_item_t item = NULL; 191 192 item = (auth_item_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, auth_item_get_type_id(), AUTH_CLASS_SIZE(auth_item), NULL); 193 require(item != NULL, done); 194 195done: 196 return item; 197} 198 199static auth_item_t 200auth_item_create(uint32_t type, const char * name, const void * value, size_t valueLen, uint32_t flags) 201{ 202 auth_item_t item = NULL; 203 require(name != NULL, done); 204 205 item = _auth_item_create(); 206 require(item != NULL, done); 207 208 item->type = type; 209 item->data.flags = flags; 210 item->data.name = _copy_string(name); 211 item->data.valueLength = valueLen; 212 item->bufLen = valueLen; 213 if (value) { 214 if (item->type == AI_TYPE_STRING) { 215 item->bufLen++; 216 item->data.value = calloc(1u, item->bufLen); 217 } else if (valueLen) { 218 item->data.value = calloc(1u, item->bufLen); 219 } 220 if (valueLen) { 221 memcpy(item->data.value, value, valueLen); 222 } 223 } 224 225done: 226 return item; 227} 228 229static auth_item_t 230auth_item_create_with_xpc(xpc_object_t data) 231{ 232 auth_item_t item = NULL; 233 require(data != NULL, done); 234 require(xpc_get_type(data) == XPC_TYPE_DICTIONARY, done); 235 require(xpc_dictionary_get_string(data, AUTH_XPC_ITEM_NAME) != NULL, done); 236 237 item = _auth_item_create(); 238 require(item != NULL, done); 239 240 item->data.name = _copy_string(xpc_dictionary_get_string(data, AUTH_XPC_ITEM_NAME)); 241 item->data.flags = (uint32_t)xpc_dictionary_get_uint64(data, AUTH_XPC_ITEM_FLAGS); 242 item->type = (uint32_t)xpc_dictionary_get_uint64(data, AUTH_XPC_ITEM_TYPE); 243 244 size_t len; 245 const void * value = xpc_dictionary_get_data(data, AUTH_XPC_ITEM_VALUE, &len); 246 if (value) { 247 item->bufLen = len; 248 item->data.valueLength = len; 249 item->data.value = calloc(1u, len); 250 memcpy(item->data.value, value, len); 251 } 252 253done: 254 return item; 255} 256 257#pragma mark - 258#pragma mark auth_items_t 259 260struct _auth_items_s { 261 __AUTH_BASE_STRUCT_HEADER__; 262 263 CFMutableDictionaryRef dictionary; 264 AuthorizationItemSet set; 265}; 266 267static void 268_auth_items_finalize(CFTypeRef value) 269{ 270 auth_items_t items = (auth_items_t)value; 271 272 CFReleaseNull(items->dictionary); 273 free_safe(items->set.items) 274} 275 276static Boolean 277_auth_items_equal(CFTypeRef value1, CFTypeRef value2) 278{ 279 auth_items_t items1 = (auth_items_t)value1; 280 auth_items_t items2 = (auth_items_t)value2; 281 282 return CFEqual(items1->dictionary, items2->dictionary); 283} 284 285static CFStringRef 286_auth_items_copy_description(CFTypeRef value) 287{ 288 auth_items_t items = (auth_items_t)value; 289 return CFCopyDescription(items->dictionary); 290} 291 292AUTH_TYPE_INSTANCE(auth_items, 293 .init = NULL, 294 .copy = NULL, 295 .finalize = _auth_items_finalize, 296 .equal = _auth_items_equal, 297 .hash = NULL, 298 .copyFormattingDesc = NULL, 299 .copyDebugDesc = _auth_items_copy_description 300 ); 301 302CFTypeID auth_items_get_type_id() 303{ 304 static CFTypeID type_id = _kCFRuntimeNotATypeID; 305 static dispatch_once_t onceToken; 306 307 dispatch_once(&onceToken, ^{ 308 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_items); 309 }); 310 311 return type_id; 312} 313 314static auth_items_t 315_auth_items_create(bool createDict) 316{ 317 auth_items_t items = NULL; 318 319 items = (auth_items_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, auth_items_get_type_id(), AUTH_CLASS_SIZE(auth_items), NULL); 320 require(items != NULL, done); 321 322 if (createDict) { 323 items->dictionary = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 324 } 325 326done: 327 return items; 328} 329 330auth_items_t 331auth_items_create() 332{ 333 auth_items_t items = NULL; 334 335 items = _auth_items_create(true); 336 require(items != NULL, done); 337 338done: 339 return items; 340} 341 342static bool 343_auth_items_parse_xpc(auth_items_t items, const xpc_object_t data) 344{ 345 bool result = false; 346 require(data != NULL, done); 347 require(xpc_get_type(data) == XPC_TYPE_ARRAY, done); 348 349 result = xpc_array_apply(data, ^bool(size_t index AUTH_UNUSED, xpc_object_t value) { 350 351 auth_item_t item = auth_item_create_with_xpc(value); 352 if (item) { 353 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 354 CFReleaseSafe(item); 355 } 356 357 return true; 358 }); 359 360done: 361 return result; 362} 363 364auth_items_t auth_items_create_with_xpc(const xpc_object_t data) 365{ 366 auth_items_t items = NULL; 367 368 items = _auth_items_create(true); 369 require(items != NULL, done); 370 371 _auth_items_parse_xpc(items, data); 372 373done: 374 return items; 375} 376 377auth_items_t 378auth_items_create_copy(auth_items_t copy) 379{ 380 auth_items_t items = NULL; 381 382 items = _auth_items_create(false); 383 require(items != NULL, done); 384 385 items->dictionary = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(copy->dictionary), copy->dictionary); 386 387done: 388 return items; 389} 390 391size_t 392auth_items_get_count(auth_items_t items) 393{ 394 return (size_t)CFDictionaryGetCount(items->dictionary); 395} 396 397AuthorizationItemSet * 398auth_items_get_item_set(auth_items_t items) 399{ 400 uint32_t count = (uint32_t)CFDictionaryGetCount(items->dictionary); 401 if (count) { 402 size_t size = count * sizeof(AuthorizationItem); 403 if (items->set.items == NULL) { 404 items->set.items = calloc(1u, size); 405 require(items->set.items != NULL, done); 406 } else { 407 if (count > items->set.count) { 408 items->set.items = realloc(items->set.items, size); 409 require_action(items->set.items != NULL, done, items->set.count = 0); 410 } 411 } 412 items->set.count = count; 413 CFTypeRef keys[count], values[count]; 414 CFDictionaryGetKeysAndValues(items->dictionary, keys, values); 415 for (CFIndex i = 0; i < count; i++) { 416 auth_item_t item = (auth_item_t)values[i]; 417 items->set.items[i] = *auth_item_get_auth_item(item); 418 } 419 } else { 420 items->set.count = 0; 421 } 422 423done: 424 return &items->set; 425} 426 427xpc_object_t 428auth_items_export_xpc(auth_items_t items) 429{ 430 xpc_object_t array = xpc_array_create(NULL, 0); 431 432 _cf_dictionary_iterate(items->dictionary, ^bool(CFTypeRef key AUTH_UNUSED, CFTypeRef value) { 433 auth_item_t item = (auth_item_t)value; 434 xpc_object_t xpc_data = auth_item_copy_auth_item_xpc(item); 435 xpc_array_append_value(array, xpc_data); 436 xpc_release_safe(xpc_data); 437 return true; 438 }); 439 440 return array; 441} 442 443static auth_item_t 444_find_item(auth_items_t items, const char * key) 445{ 446 auth_item_t item = NULL; 447 CFStringRef lookup = NULL; 448 require(key != NULL, done); 449 450 lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); 451 require(lookup != NULL, done); 452 453 item = (auth_item_t)CFDictionaryGetValue(items->dictionary, lookup); 454 455done: 456 CFReleaseSafe(lookup); 457 return item; 458} 459 460void 461auth_items_set_flags(auth_items_t items, const char *key, uint32_t flags) 462{ 463 auth_item_t item = _find_item(items,key); 464 if (item) { 465 item->data.flags |= flags; 466 } 467} 468 469void 470auth_items_clear_flags(auth_items_t items, const char *key, uint32_t flags) 471{ 472 auth_item_t item = _find_item(items,key); 473 if (item) { 474 item->data.flags &= ~flags; 475 } 476} 477 478uint32_t 479auth_items_get_flags(auth_items_t items, const char *key) 480{ 481 auth_item_t item = _find_item(items,key); 482 if (item) { 483 return item->data.flags; 484 } 485 486 return 0; 487} 488 489bool 490auth_items_check_flags(auth_items_t items, const char *key, uint32_t flags) 491{ 492 uint32_t current = auth_items_get_flags(items,key); 493 return flags ? (current & flags) != 0 : current == 0; 494} 495 496void 497auth_items_set_key(auth_items_t items, const char *key) 498{ 499 auth_item_t item = _find_item(items,key); 500 if (!item) { 501 item = auth_item_create(AI_TYPE_RIGHT, key, NULL, 0, 0); 502 if (item) { 503 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 504 CFReleaseSafe(item); 505 } 506 } 507} 508 509bool 510auth_items_exist(auth_items_t items, const char *key) 511{ 512 return _find_item(items,key) != NULL; 513} 514 515void 516auth_items_remove(auth_items_t items, const char *key) 517{ 518 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); 519 CFDictionaryRemoveValue(items->dictionary, lookup); 520 CFReleaseSafe(lookup); 521} 522 523void 524auth_items_remove_with_flags(auth_items_t items, uint32_t flags) 525{ 526 auth_items_iterate(items, ^bool(const char *key) { 527 if (auth_items_check_flags(items, key, flags)) { 528 auth_items_remove(items,key); 529 } 530 return true; 531 }); 532} 533 534void 535auth_items_clear(auth_items_t items) 536{ 537 CFDictionaryRemoveAllValues(items->dictionary); 538} 539 540void 541auth_items_copy(auth_items_t items, auth_items_t src) 542{ 543 auth_items_iterate(src, ^bool(const char *key) { 544 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); 545 auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup); 546 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 547 CFReleaseSafe(lookup); 548 return true; 549 }); 550} 551 552void 553auth_items_copy_xpc(auth_items_t items, const xpc_object_t src) 554{ 555 _auth_items_parse_xpc(items,src); 556} 557 558void 559auth_items_copy_with_flags(auth_items_t items, auth_items_t src, uint32_t flags) 560{ 561 auth_items_iterate(src, ^bool(const char *key) { 562 if (auth_items_check_flags(src, key, flags)) { 563 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); 564 auth_item_t item = (auth_item_t)CFDictionaryGetValue(src->dictionary, lookup); 565 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 566 CFReleaseSafe(lookup); 567 } 568 return true; 569 }); 570} 571 572bool 573auth_items_iterate(auth_items_t items, auth_items_iterator_t iter) 574{ 575 bool result = false; 576 CFTypeRef* keys = NULL; 577 CFTypeRef* values = NULL; 578 579 CFIndex count = CFDictionaryGetCount(items->dictionary); 580 keys = calloc((size_t)count, sizeof(CFTypeRef)); 581 require(keys != NULL, done); 582 583 values = calloc((size_t)count, sizeof(CFTypeRef)); 584 require(values != NULL, done); 585 586 CFDictionaryGetKeysAndValues(items->dictionary, keys, values); 587 for (CFIndex i = 0; i < count; i++) { 588 auth_item_t item = (auth_item_t)values[i]; 589 result = iter(item->data.name); 590 if (!result) { 591 break; 592 } 593 } 594 595done: 596 free_safe(keys); 597 free_safe(values); 598 return result; 599} 600 601void 602auth_items_set_string(auth_items_t items, const char *key, const char *value) 603{ 604 if (value) { 605 size_t valLen = strlen(value); 606 auth_item_t item = _find_item(items,key); 607 if (item && item->type == AI_TYPE_STRING && valLen < item->bufLen) { 608 memcpy(item->data.value, value, valLen+1); // copy null 609 item->data.valueLength = valLen; 610 } else { 611 item = auth_item_create(AI_TYPE_STRING, key, value, valLen, 0); 612 if (item) { 613 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 614 CFReleaseSafe(item); 615 } 616 } 617 } 618} 619 620const char * 621auth_items_get_string(auth_items_t items, const char *key) 622{ 623 auth_item_t item = _find_item(items,key); 624 if (item) { 625#if DEBUG 626 if (!(item->type == AI_TYPE_STRING || item->type == AI_TYPE_UNKNOWN)) { 627 LOGV("auth_items: key = %s, invalid type=%i expected=%i", 628 item->data.name, item->type, AI_TYPE_STRING); 629 } 630#endif 631 return auth_item_get_string(item); 632 } 633 634 return NULL; 635} 636 637void 638auth_items_set_data(auth_items_t items, const char *key, const void *value, size_t len) 639{ 640 if (value && len) { 641 auth_item_t item = _find_item(items,key); 642 if (item && item->type == AI_TYPE_DATA && len <= item->bufLen) { 643 memcpy(item->data.value, value, len); 644 item->data.valueLength = len; 645 } else { 646 item = auth_item_create(AI_TYPE_DATA, key, value, len, 0); 647 if (item) { 648 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 649 CFReleaseSafe(item); 650 } 651 } 652 } 653} 654 655const void * 656auth_items_get_data(auth_items_t items, const char *key, size_t *len) 657{ 658 auth_item_t item = _find_item(items,key); 659 if (item) { 660#if DEBUG 661 if (!(item->type == AI_TYPE_DATA || item->type == AI_TYPE_UNKNOWN)) { 662 LOGV("auth_items: key = %s, invalid type=%i expected=%i", 663 item->data.name, item->type, AI_TYPE_DATA); 664 } 665#endif 666 if (len) { 667 *len = item->data.valueLength; 668 } 669 return item->data.value; 670 } 671 672 return NULL; 673} 674 675void 676auth_items_set_bool(auth_items_t items, const char *key, bool value) 677{ 678 auth_item_t item = _find_item(items,key); 679 if (item && item->type == AI_TYPE_BOOL) { 680 *(bool*)item->data.value = value; 681 } else { 682 item = auth_item_create(AI_TYPE_BOOL, key, &value, sizeof(bool), 0); 683 if (item) { 684 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 685 CFReleaseSafe(item); 686 } 687 } 688} 689 690bool 691auth_items_get_bool(auth_items_t items, const char *key) 692{ 693 auth_item_t item = _find_item(items,key); 694 if (item) { 695#if DEBUG 696 if (!(item->type == AI_TYPE_BOOL || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(bool))) { 697 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", 698 item->data.name, item->type, AI_TYPE_BOOL, item->data.valueLength, sizeof(bool)); 699 } 700#endif 701 if (item->type == AI_TYPE_STRING) { 702 return atoi(auth_item_get_string(item)); 703 } 704 705 require(item->data.value != NULL, done); 706 require(item->data.valueLength == sizeof(bool), done); 707 708 return *(bool*)item->data.value; 709 } 710 711done: 712 return false; 713} 714 715void 716auth_items_set_int(auth_items_t items, const char *key, int32_t value) 717{ 718 auth_item_t item = _find_item(items,key); 719 if (item && item->type == AI_TYPE_INT) { 720 *(int32_t*)item->data.value = value; 721 } else { 722 item = auth_item_create(AI_TYPE_INT, key, &value, sizeof(int32_t), 0); 723 if (item) { 724 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 725 CFReleaseSafe(item); 726 } 727 } 728} 729 730int32_t 731auth_items_get_int(auth_items_t items, const char *key) 732{ 733 auth_item_t item = _find_item(items,key); 734 if (item) { 735#if DEBUG 736 if (!(item->type ==AI_TYPE_INT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int32_t))) { 737 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", 738 item->data.name, item->type, AI_TYPE_INT, item->data.valueLength, sizeof(int32_t)); 739 } 740#endif 741 if (item->type == AI_TYPE_STRING) { 742 return atoi(auth_item_get_string(item)); 743 } 744 745 require(item->data.value != NULL, done); 746 require(item->data.valueLength == sizeof(int32_t), done); 747 748 return *(int32_t*)item->data.value; 749 } 750 751done: 752 return 0; 753} 754 755void 756auth_items_set_uint(auth_items_t items, const char *key, uint32_t value) 757{ 758 auth_item_t item = _find_item(items,key); 759 if (item && item->type == AI_TYPE_UINT) { 760 *(uint32_t*)item->data.value = value; 761 } else { 762 item = auth_item_create(AI_TYPE_UINT, key, &value, sizeof(uint32_t), 0); 763 if (item) { 764 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 765 CFReleaseSafe(item); 766 } 767 } 768} 769 770uint32_t 771auth_items_get_uint(auth_items_t items, const char *key) 772{ 773 auth_item_t item = _find_item(items,key); 774 if (item) { 775#if DEBUG 776 if (!(item->type ==AI_TYPE_UINT || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint32_t))) { 777 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", 778 item->data.name, item->type, AI_TYPE_UINT, item->data.valueLength, sizeof(uint32_t)); 779 } 780#endif 781 if (item->type == AI_TYPE_STRING) { 782 return (uint32_t)atoi(auth_item_get_string(item)); 783 } 784 785 require(item->data.value != NULL, done); 786 require(item->data.valueLength == sizeof(uint32_t), done); 787 788 return *(uint32_t*)item->data.value; 789 } 790 791done: 792 return 0; 793} 794 795void 796auth_items_set_int64(auth_items_t items, const char *key, int64_t value) 797{ 798 auth_item_t item = _find_item(items,key); 799 if (item && item->type == AI_TYPE_INT64) { 800 *(int64_t*)item->data.value = value; 801 } else { 802 item = auth_item_create(AI_TYPE_INT64, key, &value, sizeof(int64_t), 0); 803 if (item) { 804 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 805 CFReleaseSafe(item); 806 } 807 } 808} 809 810int64_t 811auth_items_get_int64(auth_items_t items, const char *key) 812{ 813 auth_item_t item = _find_item(items,key); 814 if (item) { 815#if DEBUG 816 if (!(item->type ==AI_TYPE_INT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(int64_t))) { 817 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", 818 item->data.name, item->type, AI_TYPE_INT64, item->data.valueLength, sizeof(int64_t)); 819 } 820#endif 821 if (item->type == AI_TYPE_STRING) { 822 return atoll(auth_item_get_string(item)); 823 } 824 825 require(item->data.value != NULL, done); 826 require(item->data.valueLength == sizeof(int64_t), done); 827 828 return *(int64_t*)item->data.value; 829 } 830 831done: 832 return 0; 833} 834 835void 836auth_items_set_uint64(auth_items_t items, const char *key, uint64_t value) 837{ 838 auth_item_t item = _find_item(items,key); 839 if (item && item->type == AI_TYPE_UINT64) { 840 *(uint64_t*)item->data.value = value; 841 } else { 842 item = auth_item_create(AI_TYPE_UINT64, key, &value, sizeof(uint64_t), 0); 843 if (item) { 844 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 845 CFReleaseSafe(item); 846 } 847 } 848} 849 850uint64_t 851auth_items_get_uint64(auth_items_t items, const char *key) 852{ 853 auth_item_t item = _find_item(items,key); 854 if (item) { 855#if DEBUG 856 if (!(item->type ==AI_TYPE_UINT64 || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(uint64_t))) { 857 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", 858 item->data.name, item->type, AI_TYPE_UINT64, item->data.valueLength, sizeof(uint64_t)); 859 } 860#endif 861 if (item->type == AI_TYPE_STRING) { 862 return (uint64_t)atoll(auth_item_get_string(item)); 863 } 864 865 require(item->data.value != NULL, done); 866 require(item->data.valueLength == sizeof(uint64_t), done); 867 868 return *(uint64_t*)item->data.value; 869 } 870 871done: 872 return 0; 873} 874 875void auth_items_set_double(auth_items_t items, const char *key, double value) 876{ 877 auth_item_t item = _find_item(items,key); 878 if (item && item->type == AI_TYPE_DOUBLE) { 879 *(double*)item->data.value = value; 880 } else { 881 item = auth_item_create(AI_TYPE_DOUBLE, key, &value, sizeof(double), 0); 882 if (item) { 883 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 884 CFReleaseSafe(item); 885 } 886 } 887} 888 889double auth_items_get_double(auth_items_t items, const char *key) 890{ 891 auth_item_t item = _find_item(items,key); 892 if (item) { 893#if DEBUG 894 if (!(item->type ==AI_TYPE_DOUBLE || item->type == AI_TYPE_UNKNOWN) || (item->data.valueLength != sizeof(double))) { 895 LOGV("auth_items: key = %s, invalid type=%i expected=%i or size=%li expected=%li", 896 item->data.name, item->type, AI_TYPE_DOUBLE, item->data.valueLength, sizeof(double)); 897 } 898#endif 899 if (item->type == AI_TYPE_STRING) { 900 return atof(auth_item_get_string(item)); 901 } 902 903 require(item->data.value != NULL, done); 904 require(item->data.valueLength == sizeof(double), done); 905 906 return *(double*)item->data.value; 907 } 908 909done: 910 return 0; 911} 912 913uint32_t auth_items_get_type(auth_items_t items, const char *key) 914{ 915 auth_item_t item = _find_item(items,key); 916 if (item) { 917 return item->type; 918 } 919 920 return AI_TYPE_UNKNOWN; 921} 922 923size_t auth_items_get_length(auth_items_t items, const char *key) 924{ 925 auth_item_t item = _find_item(items,key); 926 if (item) { 927 return item->data.valueLength; 928 } 929 930 return 0; 931} 932 933void auth_items_set_value(auth_items_t items, const char *key, uint32_t type, uint32_t flags, const void *value, size_t len) 934{ 935 auth_item_t item = auth_item_create(type, key, value, len, flags); 936 if (item) { 937 CFDictionarySetValue(items->dictionary, auth_item_get_cf_key(item), item); 938 CFReleaseSafe(item); 939 } 940} 941 942#pragma mark - 943#pragma mark auth_rights_t 944 945struct _auth_rights_s { 946 __AUTH_BASE_STRUCT_HEADER__; 947 948 CFMutableArrayRef array; 949}; 950 951static void 952_auth_rights_finalize(CFTypeRef value) 953{ 954 auth_rights_t rights = (auth_rights_t)value; 955 956 CFReleaseNull(rights->array); 957} 958 959static Boolean 960_auth_rights_equal(CFTypeRef value1, CFTypeRef value2) 961{ 962 auth_rights_t rights1 = (auth_rights_t)value1; 963 auth_rights_t rights2 = (auth_rights_t)value2; 964 965 return CFEqual(rights1->array, rights2->array); 966} 967 968static CFStringRef 969_auth_rights_copy_description(CFTypeRef value) 970{ 971 auth_rights_t rights = (auth_rights_t)value; 972 return CFCopyDescription(rights->array); 973} 974 975AUTH_TYPE_INSTANCE(auth_rights, 976 .init = NULL, 977 .copy = NULL, 978 .finalize = _auth_rights_finalize, 979 .equal = _auth_rights_equal, 980 .hash = NULL, 981 .copyFormattingDesc = NULL, 982 .copyDebugDesc = _auth_rights_copy_description 983 ); 984 985static CFTypeID auth_rights_get_type_id() 986{ 987 static CFTypeID type_id = _kCFRuntimeNotATypeID; 988 static dispatch_once_t onceToken; 989 990 dispatch_once(&onceToken, ^{ 991 type_id = _CFRuntimeRegisterClass(&_auth_type_auth_rights); 992 }); 993 994 return type_id; 995} 996 997static auth_rights_t 998_auth_rights_create() 999{ 1000 auth_rights_t rights = NULL; 1001 1002 rights = (auth_rights_t)_CFRuntimeCreateInstance(kCFAllocatorDefault, auth_rights_get_type_id(), AUTH_CLASS_SIZE(auth_rights), NULL); 1003 require(rights != NULL, done); 1004 1005 rights->array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 1006 1007done: 1008 return rights; 1009} 1010 1011auth_rights_t 1012auth_rights_create() 1013{ 1014 auth_rights_t rights = _auth_rights_create(); 1015 require(rights != NULL, done); 1016 1017done: 1018 return rights; 1019} 1020 1021auth_rights_t auth_rights_create_with_xpc(const xpc_object_t data) 1022{ 1023 auth_rights_t rights = _auth_rights_create(); 1024 require(rights != NULL, done); 1025 require(data != NULL, done); 1026 require(xpc_get_type(data) == XPC_TYPE_ARRAY, done); 1027 1028 xpc_array_apply(data, ^bool(size_t index AUTH_UNUSED, xpc_object_t value) { 1029 1030 auth_item_t item = auth_item_create_with_xpc(value); 1031 if (item) { 1032 CFArrayAppendValue(rights->array, item); 1033 CFReleaseSafe(item); 1034 } 1035 1036 return true; 1037 }); 1038 1039done: 1040 return rights; 1041} 1042 1043xpc_object_t auth_rights_export_xpc(auth_rights_t rights) 1044{ 1045 xpc_object_t array = xpc_array_create(NULL, 0); 1046 1047 CFIndex count = CFArrayGetCount(rights->array); 1048 for (CFIndex i = 0; i < count; i++) { 1049 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i); 1050 xpc_object_t xpc_data = auth_item_copy_auth_item_xpc(item); 1051 xpc_array_append_value(array, xpc_data); 1052 xpc_release_safe(xpc_data); 1053 } 1054 1055 return array; 1056} 1057 1058static auth_item_t 1059_find_right_item(auth_rights_t rights, const char * key) 1060{ 1061 auth_item_t item = NULL; 1062 CFStringRef lookup = NULL; 1063 require(key != NULL, done); 1064 1065 lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); 1066 require(lookup != NULL, done); 1067 1068 CFIndex count = CFArrayGetCount(rights->array); 1069 for (CFIndex i = 0; i < count; i++) { 1070 auth_item_t tmp = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i); 1071 if (tmp && CFEqual(auth_item_get_cf_key(tmp), lookup)) { 1072 item = tmp; 1073 break; 1074 } 1075 } 1076 1077done: 1078 CFReleaseSafe(lookup); 1079 return item; 1080} 1081 1082void auth_rights_set_flags(auth_rights_t rights, const char *key, uint32_t flags) 1083{ 1084 auth_item_t item = _find_right_item(rights,key); 1085 if (item) { 1086 item->data.flags |= flags; 1087 } 1088} 1089 1090void auth_rights_clear_flags(auth_rights_t rights, const char *key, uint32_t flags) 1091{ 1092 auth_item_t item = _find_right_item(rights,key); 1093 if (item) { 1094 item->data.flags &= ~flags; 1095 } 1096} 1097 1098uint32_t auth_rights_get_flags(auth_rights_t rights, const char *key) 1099{ 1100 auth_item_t item = _find_right_item(rights,key); 1101 if (item) { 1102 return item->data.flags; 1103 } 1104 1105 return 0; 1106} 1107 1108bool auth_rights_check_flags(auth_rights_t rights, const char *key, uint32_t flags) 1109{ 1110 uint32_t current = auth_rights_get_flags(rights,key); 1111 return flags ? (current & flags) != 0 : current == 0; 1112} 1113 1114size_t auth_rights_get_count(auth_rights_t rights) 1115{ 1116 return (size_t)CFArrayGetCount(rights->array); 1117} 1118 1119void auth_rights_add(auth_rights_t rights, const char *key) 1120{ 1121 auth_item_t item = auth_item_create(AI_TYPE_RIGHT, key, NULL, 0, 0); 1122 if (item) { 1123 CFArrayAppendValue(rights->array, item); 1124 CFReleaseSafe(item); 1125 } 1126} 1127 1128bool auth_rights_exist(auth_rights_t rights, const char *key) 1129{ 1130 return (_find_right_item(rights,key) != NULL); 1131} 1132 1133void auth_rights_remove(auth_rights_t rights, const char *key) 1134{ 1135 CFStringRef lookup = CFStringCreateWithCStringNoCopy(kCFAllocatorDefault, key, kCFStringEncodingUTF8, kCFAllocatorNull); 1136 CFIndex count = CFArrayGetCount(rights->array); 1137 for (CFIndex i = 0; i < count; i++) { 1138 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i); 1139 if (CFEqual(auth_item_get_cf_key(item), lookup)) { 1140 CFArrayRemoveValueAtIndex(rights->array, i); 1141 i--; 1142 count--; 1143 } 1144 } 1145 CFReleaseSafe(lookup); 1146} 1147 1148void auth_rights_clear(auth_rights_t rights) 1149{ 1150 CFArrayRemoveAllValues(rights->array); 1151} 1152 1153bool 1154auth_rights_iterate(auth_rights_t rights, bool(^iter)(const char * key)) 1155{ 1156 bool result = false; 1157 1158 CFIndex count = CFArrayGetCount(rights->array); 1159 for (CFIndex i = 0; i < count; i++) { 1160 auth_item_t item = (auth_item_t)CFArrayGetValueAtIndex(rights->array, i); 1161 result = iter(item->data.name); 1162 if (!result) { 1163 break; 1164 } 1165 } 1166 1167 return result; 1168} 1169