1/*- 2 * Copyright (c) 2013 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2013 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#import <TargetConditionals.h> 31 32#import <Foundation/Foundation.h> 33#import <CoreFoundation/CoreFoundation.h> 34#import <CoreFoundation/CFRuntime.h> 35#import <System/sys/codesign.h> 36#import <xpc/xpc.h> 37#import <xpc/private.h> 38#import <syslog.h> 39#import <sandbox.h> 40 41#import "HeimCredCoder.h" 42#import "heimcred.h" 43#import "common.h" 44 45/* 46 * 47 */ 48struct HeimMech_s { 49 CFRuntimeBase runtime; 50 CFStringRef name; 51 CFSetRef publicAttributes; 52 HeimCredAuthCallback callback; 53}; 54 55static NSString *archivePath = NULL; 56 57static void 58FlattenCredential(const void *key, const void *value, void *context) 59{ 60 HeimCredRef cred = (HeimCredRef)value; 61 id nskey = [HeimCredDecoder copyCF2NS:key]; 62 id attrs = [HeimCredDecoder copyCF2NS:cred->attributes]; 63 NSMutableDictionary *flatten = context; 64 [flatten setObject:attrs forKey:nskey]; 65 [nskey release]; 66 [attrs release]; 67} 68 69static void 70storeCredCache(void) 71{ 72 id flatten = NULL; 73 @try { 74 flatten = [[NSMutableDictionary alloc] init]; 75 CFDictionaryApplyFunction(HeimCredCTX.items, FlattenCredential, flatten); 76 [HeimCredDecoder archiveRootObject:flatten toFile:archivePath]; 77 } @catch(NSException *e) { 78 } @finally { 79 [flatten release]; 80 } 81} 82 83static void 84readCredCache(void) 85{ 86 @autoreleasepool { 87 NSDictionary *flatten = NULL; 88 @try { 89 flatten = [HeimCredDecoder copyUnarchiveObjectWithFileSecureEncoding:archivePath]; 90 91 if (!flatten || ![flatten isKindOfClass:[NSDictionary class]]) 92 return; 93 94 [flatten enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) { 95 CFUUIDRef cfkey = [HeimCredDecoder copyNS2CF:key]; 96 CFDictionaryRef cfvalue = [HeimCredDecoder copyNS2CF:value]; 97 if (cfkey && cfvalue) { 98 HeimCredRef cred = HeimCredCreateItem(cfkey); 99 cred->attributes = cfvalue; 100 CFRetain(cfvalue); 101 CFDictionarySetValue(HeimCredCTX.items, cred->uuid, cred); 102 } 103 CFRELEASE_NULL(cfkey); 104 CFRELEASE_NULL(cfvalue); 105 }]; 106 } @catch(NSException *e) { 107 syslog(LOG_ERR, "readCredCache failed with: %s:%s", [[e name] UTF8String], [[e reason] UTF8String]); 108 } 109 } 110} 111 112struct peer { 113 xpc_connection_t peer; 114 CFStringRef bundleID; 115}; 116 117static bool 118checkACLInCredentialChain(struct peer *peer, CFUUIDRef uuid, bool *hasACL) 119{ 120 int max_depth = 10; 121 bool res = false; 122 123 if (hasACL) 124 *hasACL = false; 125 126 while (1) { 127 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(HeimCredCTX.items, uuid); 128 CFUUIDRef parent; 129 130 if (cred == NULL) 131 goto pass; 132 133 if (max_depth-- < 0) 134 goto out; 135 136 CFArrayRef array = CFDictionaryGetValue(cred->attributes, kHEIMAttrBundleIdentifierACL); 137 if (array) { 138 CFIndex n, count; 139 140 if (hasACL) 141 *hasACL = true; 142 143 if (CFGetTypeID(array) != CFArrayGetTypeID()) 144 goto out; 145 146 count = CFArrayGetCount(array); 147 for (n = 0; n < count; n++) { 148 CFStringRef prefix = CFArrayGetValueAtIndex(array, n); 149 150 if (CFGetTypeID(prefix) != CFStringGetTypeID()) 151 goto out; 152 153 if (CFStringHasPrefix(peer->bundleID, prefix)) 154 goto pass; 155 156 if (CFStringCompare(CFSTR("*"), prefix, 0) == kCFCompareEqualTo) 157 goto pass; 158 } 159 if (n >= count) 160 goto out; 161 } 162 163 parent = CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential); 164 if (parent == NULL) 165 goto out; 166 167 if (CFEqual(parent, uuid)) 168 break; 169 170 uuid = parent; 171 } 172 173 pass: 174 res = true; 175 176 out: 177 return res; 178} 179 180static bool 181addPeerToACL(struct peer *peer, CFMutableDictionaryRef attrs) 182{ 183 CFArrayRef acl = CFDictionaryGetValue(attrs, kHEIMAttrBundleIdentifierACL); 184 if (acl == NULL || CFGetTypeID(acl) != CFArrayGetTypeID()) 185 return false; 186 187 if (!CFArrayContainsValue(acl, CFRangeMake(0, CFArrayGetCount(acl)), peer->bundleID)) { 188 CFMutableArrayRef a = CFArrayCreateMutableCopy(NULL, 0, acl); 189 if (a == NULL) 190 return false; 191 CFArrayAppendValue(a, peer->bundleID); 192 CFDictionarySetValue(attrs, kHEIMAttrBundleIdentifierACL, a); 193 acl = a; 194 CFRELEASE_NULL(a); 195 } 196 197 return true; 198} 199 200static void 201do_CreateCred(struct peer *peer, xpc_object_t request, xpc_object_t reply) 202{ 203 CFMutableDictionaryRef attrs = NULL; 204 HeimCredRef cred = NULL; 205 CFUUIDRef uuid = NULL; 206 bool hasACL = false; 207 208 CFDictionaryRef attributes = HeimCredMessageCopyAttributes(request, "attributes"); 209 if (attributes == NULL) 210 return; 211 212 /* check if we are ok to link into this cred-tree */ 213 uuid = CFDictionaryGetValue(attributes, kHEIMAttrParentCredential); 214 if (uuid != NULL && !checkACLInCredentialChain(peer, uuid, &hasACL)) 215 return; 216 217 uuid = CFDictionaryGetValue(attributes, kHEIMAttrUUID); 218 if (uuid) { 219 CFRetain(uuid); 220 221 if (CFDictionaryGetValue(HeimCredCTX.items, uuid) != NULL) 222 goto out; 223 224 } else { 225 uuid = CFUUIDCreate(NULL); 226 if (uuid == NULL) 227 goto out; 228 } 229 cred = HeimCredCreateItem(uuid); 230 if (cred == NULL) 231 goto out; 232 233 /* XXX filter attributes */ 234 235 attrs= CFDictionaryCreateMutableCopy(NULL, 0, attributes); 236 if (attrs == NULL) 237 goto out; 238 239 bool hasACLInAttributes = addPeerToACL(peer, attrs); 240 241 /* make sure this cred-tree as an ACL */ 242 if (!hasACL && !hasACLInAttributes) { 243 const void *values[1] = { (void *)peer->bundleID }; 244 CFArrayRef array = CFArrayCreate(NULL, values, sizeof(values)/sizeof(values[0]), &kCFTypeArrayCallBacks); 245 if (array == NULL) abort(); 246 CFDictionarySetValue(attrs, kHEIMAttrBundleIdentifierACL, array); 247 CFRELEASE_NULL(array); 248 } 249 250 251 252 CFDictionarySetValue(attrs, kHEIMAttrUUID, uuid); 253 254 /* make sure credential always are have a parent and group */ 255 if (CFDictionaryGetValue(attrs, kHEIMAttrParentCredential) == NULL) 256 CFDictionarySetValue(attrs, kHEIMAttrParentCredential, uuid); 257 if (CFDictionaryGetValue(attrs, kHEIMAttrCredentialGroup) == NULL) 258 CFDictionarySetValue(attrs, kHEIMAttrCredentialGroup, uuid); 259 260 cred->attributes = attrs; 261 262 CFDictionarySetValue(HeimCredCTX.items, cred->uuid, cred); 263 264 HeimCredMessageSetAttributes(reply, "attributes", cred->attributes); 265out: 266 CFRELEASE_NULL(attributes); 267 CFRELEASE_NULL(cred); 268 CFRELEASE_NULL(uuid); 269} 270 271struct MatchCTX { 272 struct peer *peer; 273 CFMutableArrayRef results; 274 CFDictionaryRef query; 275 CFIndex numQueryItems; 276 HeimCredRef cred; 277 CFIndex count; 278}; 279 280static void 281MatchQueryItem(const void *key, const void *value, void *context) 282{ 283 struct MatchCTX * mc = (struct MatchCTX *)context; 284 if (mc->cred->attributes == NULL) 285 return; 286 CFTypeRef val = CFDictionaryGetValue(mc->cred->attributes, key); 287 if (val == NULL) 288 return; 289 if (!CFEqual(val, value)) 290 return; 291 mc->count++; 292} 293 294static void 295MatchQuery(const void *key, const void *value, void *context) 296{ 297 struct MatchCTX *mc = (struct MatchCTX *)context; 298 CFUUIDRef uuid = (CFUUIDRef)key; 299 300 if (!checkACLInCredentialChain(mc->peer, uuid, NULL)) 301 return; 302 303 HeimCredRef cred = (HeimCredRef)value; 304 if (cred->attributes == NULL) 305 return; 306 mc->cred = cred; 307 mc->count = 0; 308 CFDictionaryApplyFunction(mc->query, MatchQueryItem, mc); 309 if (mc->numQueryItems < mc->count) abort(); 310 if (mc->numQueryItems == mc->count) 311 CFArrayAppendValue(mc->results, cred); 312} 313 314 315static CFArrayRef 316QueryCopy(struct peer *peer, xpc_object_t request, const char *key) 317{ 318 struct MatchCTX mc = { 319 .peer = peer, 320 .results = NULL, 321 .query = NULL, 322 .cred = NULL, 323 }; 324 CFUUIDRef uuidref = NULL; 325 326 327 mc.query = HeimCredMessageCopyAttributes(request, key); 328 if (mc.query == NULL) 329 goto out; 330 331 mc.numQueryItems = CFDictionaryGetCount(mc.query); 332 333 if (mc.numQueryItems == 1) { 334 uuidref = CFDictionaryGetValue(mc.query, kHEIMAttrUUID); 335 if (uuidref && CFGetTypeID(uuidref) == CFUUIDGetTypeID()) { 336 337 if (!checkACLInCredentialChain(peer, uuidref, NULL)) 338 goto out; 339 340 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(HeimCredCTX.items, uuidref); 341 342 const void *values[1] = { (void *)cred } ; 343 344 mc.results = (CFMutableArrayRef)CFArrayCreate(NULL, (const void **)&values, cred ? 1 : 0, &kCFTypeArrayCallBacks); 345 goto out; 346 } 347 } 348 349 mc.results = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 350 351 CFDictionaryApplyFunction(HeimCredCTX.items, MatchQuery, &mc); 352 353out: 354 CFRELEASE_NULL(mc.query); 355 return mc.results; 356} 357 358struct child { 359 CFUUIDRef parent; 360 CFMutableArrayRef array; 361}; 362 363static void 364DeleteChild(const void *key, const void *value, void *context) 365{ 366 struct child *child = (struct child *)context; 367 368 if (CFEqual(key, child->parent)) 369 return; 370 371 HeimCredRef cred = (HeimCredRef)value; 372 CFUUIDRef parent = CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential); 373 if (parent && CFEqual(child->parent, parent)) 374 CFArrayAppendValue(child->array, cred->uuid); 375} 376 377static void 378DeleteChildrenApplier(const void *value, void *context) 379{ 380 if (CFGetTypeID(value) != CFUUIDGetTypeID()) abort(); 381 CFDictionaryRemoveValue(HeimCredCTX.items, value); 382} 383 384 385static void 386DeleteChildren(CFUUIDRef parent) 387{ 388 /* 389 * delete all child entries for to UUID 390 */ 391 struct child child = { 392 .parent = parent, 393 .array = NULL, 394 }; 395 child.array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 396 CFDictionaryApplyFunction(HeimCredCTX.items, DeleteChild, &child); 397 CFArrayApplyFunction(child.array, CFRangeMake(0, CFArrayGetCount(child.array)), DeleteChildrenApplier, NULL); 398 CFRelease(child.array); 399} 400 401struct fromto { 402 CFUUIDRef from; 403 CFUUIDRef to; 404}; 405 406static void 407UpdateParent(const void *key, const void *value, void *context) 408{ 409 struct fromto *fromto = (struct fromto *)context; 410 HeimCredRef cred = (HeimCredRef)value; 411 CFUUIDRef parent = CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential); 412 if (parent && CFEqual(parent, fromto->from)) { 413 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, cred->attributes); 414 CFRelease(cred->attributes); 415 CFDictionarySetValue(attrs, kHEIMAttrParentCredential, fromto->to); 416 CFDictionarySetValue(attrs, kHEIMAttrCredentialGroup, fromto->to); 417 cred->attributes = attrs; 418 } 419} 420 421 422 423 424static void 425do_Delete(struct peer *peer, xpc_object_t request, xpc_object_t reply) 426{ 427 CFArrayRef items = QueryCopy(peer, request, "query"); 428 if (items == NULL) 429 return; 430 431 CFIndex n, count = CFArrayGetCount(items); 432 for (n = 0; n < count; n++) { 433 HeimCredRef cred = (HeimCredRef)CFArrayGetValueAtIndex(items, n); 434 CFDictionaryRemoveValue(HeimCredCTX.items, cred->uuid); 435 DeleteChildren(cred->uuid); 436 } 437 CFRelease(items); 438} 439 440static void 441updateCred(const void *key, const void *value, void *context) 442{ 443 CFMutableDictionaryRef attrs = (CFMutableDictionaryRef)context; 444 /* XXX filter keys */ 445 CFDictionarySetValue(attrs, key, value); 446} 447 448 449static void 450do_SetAttrs(struct peer *peer, xpc_object_t request, xpc_object_t reply) 451{ 452 CFUUIDRef uuid = HeimCredCopyUUID(request, "uuid"); 453 CFMutableDictionaryRef attrs; 454 455 if (uuid == NULL) 456 return; 457 458 if (!checkACLInCredentialChain(peer, uuid, NULL)) 459 return; 460 461 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(HeimCredCTX.items, uuid); 462 CFRelease(uuid); 463 if (cred == NULL) 464 return; 465 466 if (cred->attributes) { 467 attrs = CFDictionaryCreateMutableCopy(NULL, 0, cred->attributes); 468 if (attrs == NULL) 469 return; 470 } else { 471 attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 472 } 473 474 CFDictionaryRef replacementAttrs = HeimCredMessageCopyAttributes(request, "attributes"); 475 if (replacementAttrs == NULL) { 476 CFRelease(attrs); 477 return; 478 } 479 CFDictionaryApplyFunction(replacementAttrs, updateCred, attrs); 480 CFRELEASE_NULL(replacementAttrs); 481 482 /* make sure the current caller is on the ACL list */ 483 addPeerToACL(peer, attrs); 484 485 CFRELEASE_NULL(cred->attributes); 486 cred->attributes = attrs; 487} 488 489static void 490do_Fetch(struct peer *peer, xpc_object_t request, xpc_object_t reply) 491{ 492 CFUUIDRef uuid = HeimCredCopyUUID(request, "uuid"); 493 if (uuid == NULL) 494 return; 495 496 if (!checkACLInCredentialChain(peer, uuid, NULL)) 497 return; 498 499 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(HeimCredCTX.items, uuid); 500 CFRelease(uuid); 501 if (cred == NULL) 502 return; 503 504 /* XXX filter the attributes */ 505 506 HeimCredMessageSetAttributes(reply, "attributes", cred->attributes); 507} 508 509static void 510do_Query(struct peer *peer, xpc_object_t request, xpc_object_t reply) 511{ 512 CFArrayRef items = QueryCopy(peer, request, "query"); 513 if (items == NULL) 514 return; 515 516 CFMutableArrayRef array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 517 if (array == NULL) { 518 CFRELEASE_NULL(items); 519 return; 520 } 521 522 CFIndex n, count = CFArrayGetCount(items); 523 for (n = 0; n < count; n++) { 524 HeimCredRef cred = (HeimCredRef)CFArrayGetValueAtIndex(items, n); 525 CFArrayAppendValue(array, cred->uuid); 526 } 527 CFRELEASE_NULL(items); 528 529 HeimCredMessageSetAttributes(reply, "items", array); 530 CFRELEASE_NULL(array); 531} 532 533static void 534do_Move(struct peer *peer, xpc_object_t request, xpc_object_t reply) 535{ 536 CFUUIDRef from = (CFUUIDRef)HeimCredMessageCopyAttributes(request, "from"); 537 CFUUIDRef to = (CFUUIDRef)HeimCredMessageCopyAttributes(request, "to"); 538 539 if (!checkACLInCredentialChain(peer, from, NULL) || !checkACLInCredentialChain(peer, to, NULL)) 540 return; 541 542 HeimCredRef credfrom = (HeimCredRef)CFDictionaryGetValue(HeimCredCTX.items, from); 543 HeimCredRef credto = (HeimCredRef)CFDictionaryGetValue(HeimCredCTX.items, to); 544 545 CFMutableDictionaryRef newattrs = CFDictionaryCreateMutableCopy(NULL, 0, credfrom->attributes); 546 CFDictionaryRemoveValue(HeimCredCTX.items, from); 547 credfrom = NULL; 548 549 CFDictionarySetValue(newattrs, kHEIMAttrUUID, to); 550 CFDictionarySetValue(newattrs, kHEIMAttrCredentialGroup, to); 551 552 if (credto == NULL) { 553 credto = HeimCredCreateItem(to); 554 if (credto == NULL) abort(); 555 credto->attributes = newattrs; 556 CFDictionarySetValue(HeimCredCTX.items, credto->uuid, credto); 557 CFRelease(credto); 558 559 } else { 560 CFUUIDRef parentUUID = CFDictionaryGetValue(credto->attributes, kHEIMAttrParentCredential); 561 if (parentUUID) 562 CFDictionarySetValue(newattrs, kHEIMAttrParentCredential, parentUUID); 563 CFRELEASE_NULL(credto->attributes); 564 credto->attributes = newattrs; 565 } 566 567 /* 568 * delete all child entries for to UUID 569 */ 570 DeleteChildren(to); 571 572 /* 573 * update all child entries for from UUID 574 */ 575 struct fromto fromto = { 576 .from = from, 577 .to = to, 578 }; 579 CFDictionaryApplyFunction(HeimCredCTX.items, UpdateParent, &fromto); 580} 581 582 583static void GSSCred_peer_event_handler(struct peer *peer, xpc_object_t event) 584{ 585 xpc_object_t reply = NULL; 586 xpc_type_t type = xpc_get_type(event); 587 if (type == XPC_TYPE_ERROR) 588 return; 589 590 assert(type == XPC_TYPE_DICTIONARY); 591 592 const char *cmd = xpc_dictionary_get_string(event, "command"); 593 if (cmd == NULL) { 594 xpc_connection_cancel(peer->peer); 595 } else if (strcmp(cmd, "wakeup") == 0) { 596 597 } else if (strcmp(cmd, "create") == 0) { 598 reply = xpc_dictionary_create_reply(event); 599 do_CreateCred(peer, event, reply); 600 } else if (strcmp(cmd, "delete") == 0) { 601 reply = xpc_dictionary_create_reply(event); 602 do_Delete(peer, event, reply); 603 } else if (strcmp(cmd, "setattributes") == 0) { 604 reply = xpc_dictionary_create_reply(event); 605 do_SetAttrs(peer, event, reply); 606 } else if (strcmp(cmd, "fetch") == 0) { 607 reply = xpc_dictionary_create_reply(event); 608 do_Fetch(peer, event, reply); 609 } else if (strcmp(cmd, "move") == 0) { 610 reply = xpc_dictionary_create_reply(event); 611 do_Move(peer, event, reply); 612 } else if (strcmp(cmd, "query") == 0) { 613 reply = xpc_dictionary_create_reply(event); 614 do_Query(peer, event, reply); 615 } else if (strcmp(cmd, "retain-transient") == 0) { 616 reply = xpc_dictionary_create_reply(event); 617 } else if (strcmp(cmd, "release-transient") == 0) { 618 reply = xpc_dictionary_create_reply(event); 619 } else { 620 syslog(LOG_ERR, "peer sent invalid command %s", cmd); 621 xpc_connection_cancel(peer->peer); 622 } 623 624 if (reply) { 625 xpc_connection_send_message(peer->peer, reply); 626 xpc_release(reply); 627 } 628 629 storeCredCache(); 630} 631 632static void 633peer_final(void *ptr) 634{ 635 struct peer *peer = ptr; 636 CFRELEASE_NULL(peer->bundleID); 637} 638 639static CFStringRef 640CopySigningIdentitier(xpc_connection_t conn) 641{ 642 uint8_t header[8] = { 0 }; 643 uint32_t len; 644 audit_token_t audit_token; 645 pid_t pid; 646 647 pid = xpc_connection_get_pid(conn); 648 xpc_connection_get_audit_token(conn, &audit_token); 649 650 int rcent = csops_audittoken(pid, CS_OPS_IDENTITY, header, sizeof(header), &audit_token); 651 if (rcent != -1 || errno != ERANGE) 652 return NULL; 653 654 655 memcpy(&len, &header[4], 4); 656 len = ntohl(len); 657 if (len > 1024 * 1024) 658 return NULL; 659 else if (len == 0) 660 return NULL; 661 662 uint8_t buffer[len]; 663 664 rcent = csops_audittoken(pid, CS_OPS_IDENTITY, buffer, len, &audit_token); 665 if (rcent != 0) 666 return NULL; 667 668 char *p = (char *)buffer; 669 if (len > 8) { 670 p += 8; 671 len -= 8; 672 } else 673 return NULL; 674 675 return CFStringCreateWithBytes(NULL, (UInt8 *)p, len, kCFStringEncodingUTF8, false); 676} 677 678static void GSSCred_event_handler(xpc_connection_t peerconn) 679{ 680 struct peer *peer; 681 682 peer = malloc(sizeof(*peer)); 683 if (peer == NULL) abort(); 684 685 peer->peer = peerconn; 686 peer->bundleID = CopySigningIdentitier(peerconn); 687 if (peer->bundleID == NULL) { 688 free(peer); 689 xpc_connection_cancel(peerconn); 690 return; 691 } 692 693 xpc_connection_set_context(peerconn, peer); 694 xpc_connection_set_finalizer_f(peerconn, peer_final); 695 696 xpc_connection_set_event_handler(peerconn, ^(xpc_object_t event) { 697 GSSCred_peer_event_handler(peer, event); 698 }); 699 xpc_connection_resume(peerconn); 700} 701 702int main(int argc, const char *argv[]) 703{ 704#if TARGET_OS_EMBEDDED 705 char *error = NULL; 706 707 if (sandbox_init("com.apple.GSSCred", SANDBOX_NAMED, &error)) { 708 syslog(LOG_ERR, "failed to enter sandbox: %s", error); 709 exit(EXIT_FAILURE); 710 } 711#endif 712 713#if TARGET_IPHONE_SIMULATOR 714 archivePath = [[NSString alloc] initWithFormat:@"%@/Library/Caches/com.apple.GSSCred.simulator-archive", NSHomeDirectory()]; 715#elif TARGET_OS_EMBEDDED 716 archivePath = @"/var/db/heim-credential-store.archive"; 717#else 718 archivePath = [[NSString alloc] initWithFormat:@"%@/Library/Caches/com.apple.GSSCred.archive", NSHomeDirectory()]; 719#endif 720 721 _HeimCredInitCommon(); 722 readCredCache(); 723 xpc_main(GSSCred_event_handler); 724 return 0; 725} 726