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 <servers/bootstrap.h> 37#import <bsm/audit.h> 38#import <bsm/audit_session.h> 39#import <bsm/libbsm.h> 40#import <xpc/xpc.h> 41#import <xpc/private.h> 42#import <libproc.h> 43#import <syslog.h> 44#import <sandbox.h> 45#import <launch.h> 46#import <launch_priv.h> 47 48#import <dispatch/dispatch.h> 49#import <notify.h> 50#import <mach/mach.h> 51#import <mach/mach_time.h> 52 53#import <roken.h> 54 55#import "HeimCredCoder.h" 56#import "heimcred.h" 57#import "common.h" 58#import "heimbase.h" 59#import "hc_err.h" 60 61/* 62 * 63 */ 64 65static bool validateObject(CFDictionaryRef, CFErrorRef *); 66static void addErrorToReply(xpc_object_t, CFErrorRef); 67static CFTypeRef GetValidatedValue(CFDictionaryRef, CFStringRef, CFTypeID, CFErrorRef *); 68static void HCMakeError(CFErrorRef *, CFIndex, const void *const *, const void *const *, CFIndex); 69static CFTypeID getSessionTypeID(void); 70static struct HeimSession *HeimCredCopySession(int); 71static void handleDefaultCredentialUpdate(struct HeimSession *, HeimCredRef, CFDictionaryRef); 72 73 74/* 75 * 76 */ 77struct HeimSession { 78 CFRuntimeBase runtime; 79 uid_t session; 80 CFMutableDictionaryRef items; 81 CFMutableDictionaryRef defaultCredentials; 82 int updateDefaultCredential; 83}; 84 85/* 86 * 87 */ 88struct HeimMech { 89 CFRuntimeBase runtime; 90 CFStringRef name; 91 HeimCredStatusCallback statusCallback; 92 HeimCredAuthCallback authCallback; 93}; 94 95 96 97static NSString *archivePath = NULL; 98static dispatch_queue_t runQueue; 99 100static void 101FlattenCredential(const void *key, const void *value, void *context) 102{ 103 NSMutableDictionary *flatten = (NSMutableDictionary *)context; 104 HeimCredRef cred = (HeimCredRef)value; 105 id nskey = [HeimCredDecoder copyCF2NS:key]; 106 id attrs = [HeimCredDecoder copyCF2NS:cred->attributes]; 107 [flatten setObject:attrs forKey:nskey]; 108 [nskey release]; 109 [attrs release]; 110} 111 112static void 113FlattenSession(const void *key, const void *value, void *context) 114{ 115 NSMutableDictionary *sf = (NSMutableDictionary *)context; 116 id cf = NULL; 117 @try { 118 struct HeimSession *session = (struct HeimSession *)value; 119 cf = [[NSMutableDictionary alloc] init]; 120 CFDictionaryApplyFunction(session->items, FlattenCredential, cf); 121 [sf setObject:cf forKey:[NSNumber numberWithInt:(int)session->session]]; 122 } @catch(NSException * __unused e) { 123 } @finally { 124 [cf release]; 125 } 126} 127 128 129static void 130storeCredCache(void) 131{ 132 id sf = NULL; 133 @try { 134 sf = [[NSMutableDictionary alloc] init]; 135 CFDictionaryApplyFunction(HeimCredCTX.sessions, FlattenSession, sf); 136 [HeimCredDecoder archiveRootObject:sf toFile:archivePath]; 137 } @catch(NSException * __unused e) { 138 } @finally { 139 [sf release]; 140 } 141} 142 143static uint64_t 144relative_nano_time(void) 145{ 146 static uint64_t factor; 147 uint64_t now; 148 149 now = mach_absolute_time(); 150 151 if (factor == 0) { 152 mach_timebase_info_data_t base; 153 (void)mach_timebase_info(&base); 154 factor = base.numer / base.denom; 155 } 156 157 return now * factor; 158} 159 160#define KRB5_KCM_NOTIFY_CACHE_CHANGED "com.apple.Kerberos.cache.changed" 161 162static void 163notifyChangedCaches(void) 164{ 165 static uint64_t last_change; 166 static int notify_pending; 167 168#define NOTIFY_TIME_LIMIT (NSEC_PER_SEC / 2) 169 170 dispatch_async(dispatch_get_main_queue(), ^{ 171 uint64_t now, diff; 172 173 if (notify_pending) 174 return; 175 176 now = relative_nano_time(); 177 if (now < last_change) 178 diff = NOTIFY_TIME_LIMIT; 179 else 180 diff = now - last_change; 181 182 if (diff >= NOTIFY_TIME_LIMIT) { 183 notify_post(KRB5_KCM_NOTIFY_CACHE_CHANGED); 184 last_change = now; 185 } else { 186 notify_pending = 1; 187 /* wait up to deliver the event */ 188 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NOTIFY_TIME_LIMIT - diff), dispatch_get_main_queue(), ^{ 189 notify_pending = 0; 190 last_change = relative_nano_time(); 191 notify_post(KRB5_KCM_NOTIFY_CACHE_CHANGED); 192 }); 193 } 194 }); 195} 196 197static bool 198HeimCredAssignMech(HeimCredRef cred, CFDictionaryRef attributes) 199{ 200 heim_assert(cred->mech == NULL, "HeimCredAssignMech already have a mech"); 201 202 CFErrorRef error = NULL; 203 CFStringRef mechName = GetValidatedValue(attributes, kHEIMAttrType, CFStringGetTypeID(), &error); 204 205 if (mechName) { 206 struct HeimMech *mech = (struct HeimMech *)CFDictionaryGetValue(HeimCredCTX.mechanisms, mechName); 207 if (mech) { 208 cred->mech = mech; 209 return true; 210 } 211 } 212 CFRELEASE_NULL(error); 213 return false; 214} 215 216static bool 217sessionExists(pid_t asid) 218{ 219 auditinfo_addr_t aia; 220 aia.ai_asid = asid; 221 222 if (audit_get_sinfo_addr(&aia, sizeof(aia)) == 0) 223 return true; 224 return false; 225} 226 227static void 228readCredCache(void) 229{ 230 @autoreleasepool { 231 NSDictionary *sessions = NULL; 232 @try { 233 sessions = [HeimCredDecoder copyUnarchiveObjectWithFileSecureEncoding:archivePath]; 234 235 if (!sessions || ![sessions isKindOfClass:[NSDictionary class]]) 236 return; 237 238 [sessions enumerateKeysAndObjectsUsingBlock:^(id skey, id svalue, BOOL *sstop) { 239 int sessionID = [(NSNumber *)skey intValue]; 240 241 if (!sessionExists(sessionID)) 242 return; 243 244 struct HeimSession *session = HeimCredCopySession(sessionID); 245 if (session == NULL) 246 return; 247 248 NSDictionary *creds = (NSDictionary *)svalue; 249 250 if (!creds || ![creds isKindOfClass:[NSDictionary class]]) { 251 CFRelease(session); 252 return; 253 } 254 255 [creds enumerateKeysAndObjectsUsingBlock:^(id ckey, id cvalue, BOOL *cstop) { 256 CFUUIDRef cfkey = [HeimCredDecoder copyNS2CF:ckey]; 257 CFDictionaryRef cfvalue = [HeimCredDecoder copyNS2CF:cvalue]; 258 if (cfkey && cfvalue) { 259 HeimCredRef cred = HeimCredCreateItem(cfkey); 260 261 if (HeimCredAssignMech(cred, cfvalue)) { 262 cred->attributes = CFRetain(cfvalue); 263 CFDictionarySetValue(session->items, cred->uuid, cred); 264 265 handleDefaultCredentialUpdate(session, cred, cred->attributes); 266 } else { 267 /* dropping cred if mech assignment failed */ 268 CFRelease(cred); 269 } 270 } 271 CFRELEASE_NULL(cfkey); 272 CFRELEASE_NULL(cfvalue); 273 }]; 274 275 CFRelease(session); 276 }]; 277 } @catch(NSException *e) { 278 syslog(LOG_ERR, "readCredCache failed with: %s:%s", [[e name] UTF8String], [[e reason] UTF8String]); 279 } 280 } 281} 282 283struct peer { 284 xpc_connection_t peer; 285 CFStringRef bundleID; 286 struct HeimSession *session; 287}; 288 289/* 290 * Check if the credential (uuid) have an ACL and while not having an 291 * ACL, walk up the parent chain and check if any other parents have 292 * an ACL. 293 */ 294 295static bool 296checkACLInCredentialChain(struct peer *peer, CFUUIDRef uuid, bool *hasACL) 297{ 298 int max_depth = 10; 299 bool res = false; 300 301 if (hasACL) 302 *hasACL = false; 303 304 while (1) { 305 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(peer->session->items, uuid); 306 CFUUIDRef parent; 307 308 if (cred == NULL) 309 goto pass; 310 311 heim_assert(CFGetTypeID(cred) == HeimCredGetTypeID(), "cred wrong type"); 312 313 if (max_depth-- < 0) 314 goto out; 315 316 CFArrayRef array = CFDictionaryGetValue(cred->attributes, kHEIMAttrBundleIdentifierACL); 317 if (array) { 318 CFIndex n, count; 319 320 if (hasACL) 321 *hasACL = true; 322 323 if (CFGetTypeID(array) != CFArrayGetTypeID()) 324 goto out; 325 326 count = CFArrayGetCount(array); 327 for (n = 0; n < count; n++) { 328 CFStringRef prefix = CFArrayGetValueAtIndex(array, n); 329 330 if (CFGetTypeID(prefix) != CFStringGetTypeID()) 331 goto out; 332 333#if !TARGET_OS_EMBEDDED 334 if (CFEqual(prefix, CFSTR("*"))) 335 goto pass; 336#endif 337 if (CFEqual(peer->bundleID, prefix)) 338 goto pass; 339 340 NSPredicate *wildCardMatch = [NSPredicate predicateWithFormat:@"self like %@", prefix]; 341 BOOL matchFound = [wildCardMatch evaluateWithObject:(NSString *)peer->bundleID]; 342 343 if (matchFound) 344 goto pass; 345 } 346 if (n >= count) 347 goto out; 348 } 349 350 parent = CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential); 351 if (parent == NULL) 352 goto out; 353 354 if (CFEqual(parent, uuid)) 355 break; 356 357 uuid = parent; 358 } 359 360 pass: 361 res = true; 362 363 out: 364 return res; 365} 366 367static bool 368addPeerToACL(struct peer *peer, CFMutableDictionaryRef attrs) 369{ 370 CFArrayRef acl = CFDictionaryGetValue(attrs, kHEIMAttrBundleIdentifierACL); 371 if (acl == NULL || CFGetTypeID(acl) != CFArrayGetTypeID()) 372 return false; 373 374 if (!CFArrayContainsValue(acl, CFRangeMake(0, CFArrayGetCount(acl)), peer->bundleID)) { 375 CFMutableArrayRef a = CFArrayCreateMutableCopy(NULL, 0, acl); 376 if (a == NULL) 377 return false; 378 CFArrayAppendValue(a, peer->bundleID); 379 CFDictionarySetValue(attrs, kHEIMAttrBundleIdentifierACL, a); 380 CFRELEASE_NULL(a); 381 } 382 383 return true; 384} 385 386static void 387updateStoreTime(HeimCredRef cred, CFMutableDictionaryRef attrs) 388{ 389 CFDateRef date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); 390 if (date == NULL) 391 return; 392 CFDictionarySetValue(attrs, kHEIMAttrStoreTime, date); 393 CFRelease(date); 394} 395 396static void 397handleDefaultCredentialUpdate(struct HeimSession *session, HeimCredRef cred, CFDictionaryRef attrs) 398{ 399 400 heim_assert(cred->mech != NULL, "mech is NULL, schame validation doesn't work ?"); 401 402 CFUUIDRef oldDefault = CFDictionaryGetValue(session->defaultCredentials, cred->mech->name); 403 404 CFBooleanRef defaultCredential = CFDictionaryGetValue(attrs, kHEIMAttrDefaultCredential); 405 if (defaultCredential == NULL || !CFBooleanGetValue(defaultCredential)) { 406 if (oldDefault) 407 return; 408 } else { 409 if (oldDefault) { 410 /* 411 * Drop marker on old credential 412 */ 413 HeimCredRef oldCred = (HeimCredRef)CFDictionaryGetValue(session->items, oldDefault); 414 if (oldCred) { 415 CFMutableDictionaryRef oldCredAttrs = CFDictionaryCreateMutableCopy(NULL, 0, oldCred->attributes); 416 CFDictionaryRemoveValue(oldCredAttrs, kHEIMAttrDefaultCredential); 417 CFRELEASE_NULL(oldCred->attributes); 418 oldCred->attributes = oldCredAttrs; 419 } 420 } 421 } 422 423 CFDictionarySetValue(session->defaultCredentials, cred->mech->name, cred->uuid); 424 425 notifyChangedCaches(); 426} 427 428static void 429handleDefaultCredentialDeletion(struct HeimSession *session, HeimCredRef cred) 430{ 431 CFUUIDRef defaultCredential = CFDictionaryGetValue(session->defaultCredentials, cred->mech->name); 432 433 if (defaultCredential && CFEqual(defaultCredential, cred->uuid)) 434 CFDictionaryRemoveValue(session->defaultCredentials, cred->mech->name); 435 session->updateDefaultCredential = 1; 436} 437 438static void 439reElectCredential(const void *key, const void *value, void *context) 440{ 441 HeimCredRef cred = (HeimCredRef)value; 442 struct HeimSession *session = (struct HeimSession *)context; 443 444 if (CFDictionaryGetValue(session->defaultCredentials, cred->mech->name)) 445 return; 446 if (CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential) != NULL) 447 return; 448 CFDictionarySetValue(session->defaultCredentials, cred->mech->name, cred->uuid); 449} 450 451static void 452reElectMechCredential(const void *key, const void *value, void *context) 453{ 454 struct HeimMech *mech = (struct HeimMech *)value; 455 struct HeimSession *session = (struct HeimSession *)context; 456 457 if (CFDictionaryGetValue(session->defaultCredentials, mech->name)) 458 return; 459 460 CFDictionaryApplyFunction(session->items, reElectCredential, session); 461 462 if (CFDictionaryGetValue(session->defaultCredentials, mech->name)) { 463 HeimCredCTX.needFlush = 1; 464 } else { 465 /* 466 * If there is no default credential, make one up 467 */ 468 CFUUIDRef defcred = CFUUIDCreate(NULL); 469 CFDictionarySetValue(session->defaultCredentials, mech->name, defcred); 470 CFRelease(defcred); 471 } 472 473 notifyChangedCaches(); 474} 475 476static void 477reElectDefaultCredential(struct peer *peer) 478{ 479 if (!peer->session->updateDefaultCredential) 480 return; 481 peer->session->updateDefaultCredential = 0; 482 483 CFDictionaryApplyFunction(HeimCredCTX.mechanisms, reElectMechCredential, peer->session); 484} 485 486#if TARGET_OS_EMBEDDED 487static bool 488canSetAnyBundleIDACL(struct peer *peer) 489{ 490 return CFStringCompare(CFSTR("com.apple.accountsd"), peer->bundleID, 0) == kCFCompareEqualTo; 491} 492#endif 493 494static void 495do_CreateCred(struct peer *peer, xpc_object_t request, xpc_object_t reply) 496{ 497 CFMutableDictionaryRef attrs = NULL; 498 HeimCredRef cred = NULL; 499 CFUUIDRef uuid = NULL; 500 bool hasACL = false; 501 CFErrorRef error = NULL; 502 CFBooleanRef lead; 503 504 CFDictionaryRef attributes = HeimCredMessageCopyAttributes(request, "attributes", CFDictionaryGetTypeID()); 505 if (attributes == NULL) 506 goto out; 507 508 if (!validateObject(attributes, &error)) { 509 addErrorToReply(reply, error); 510 goto out; 511 } 512 513 /* check if we are ok to link into this cred-tree */ 514 uuid = CFDictionaryGetValue(attributes, kHEIMAttrParentCredential); 515 if (uuid != NULL && !checkACLInCredentialChain(peer, uuid, &hasACL)) 516 goto out; 517 518 uuid = CFDictionaryGetValue(attributes, kHEIMAttrUUID); 519 if (uuid) { 520 CFRetain(uuid); 521 522 if (CFGetTypeID(uuid) != CFUUIDGetTypeID()) 523 goto out; 524 525 if (CFDictionaryGetValue(peer->session->items, uuid) != NULL) 526 goto out; 527 528 } else { 529 uuid = CFUUIDCreate(NULL); 530 if (uuid == NULL) 531 goto out; 532 } 533 cred = HeimCredCreateItem(uuid); 534 if (cred == NULL) 535 goto out; 536 537 attrs = CFDictionaryCreateMutableCopy(NULL, 0, attributes); 538 if (attrs == NULL) 539 goto out; 540 541 bool hasACLInAttributes = addPeerToACL(peer, attrs); 542 543#if TARGET_OS_EMBEDDED 544 if (hasACLInAttributes && !canSetAnyBundleIDACL(peer)) { 545 CFArrayRef array = CFDictionaryGetValue(attrs, kHEIMAttrBundleIdentifierACL); 546 if (array == NULL || CFGetTypeID(array) != CFArrayGetTypeID() || CFArrayGetCount(array) != 1) { 547 syslog(LOG_ERR, "peer sent more then one bundle id and is not accountsd"); 548 goto out; 549 } 550 } 551#endif 552 553 /* 554 * make sure this cred-tree as an ACL Set the ACL to be the peer 555 * on ios, and on osx, its "*" since that is the default policy. 556 * 557 * XXX should use the default keychain rule for appsandboxed peers 558 * on osx. 559 */ 560 if (!hasACL && !hasACLInAttributes) { 561#if TARGET_OS_IPHONE 562 const void *values[1] = { (void *)peer->bundleID }; 563#else 564 const void *values[1] = { CFSTR("*") }; 565#endif 566 CFArrayRef array = CFArrayCreate(NULL, values, sizeof(values)/sizeof(values[0]), &kCFTypeArrayCallBacks); 567 heim_assert(array != NULL, "out of memory"); 568 CFDictionarySetValue(attrs, kHEIMAttrBundleIdentifierACL, array); 569 CFRELEASE_NULL(array); 570 } 571 572 CFDictionarySetValue(attrs, kHEIMAttrUUID, uuid); 573 574 if (!validateObject(attrs, &error)) { 575 addErrorToReply(reply, error); 576 goto out; 577 } 578 579 if (!HeimCredAssignMech(cred, attrs)) { 580 goto out; 581 } 582 583 updateStoreTime(cred, attrs); 584 handleDefaultCredentialUpdate(peer->session, cred, attrs); 585 586 cred->attributes = CFRetain(attrs); 587 588 CFDictionarySetValue(peer->session->items, cred->uuid, cred); 589 notifyChangedCaches(); 590 HeimCredCTX.needFlush = 1; 591 592 /* 593 * If the default credential is unset or doesn't exists, switch to 594 * the now just created lead credential. 595 */ 596 597 heim_assert(cred->mech != NULL, "mech is NULL, schame validation doesn't work ?"); 598 599 CFUUIDRef defcred = CFDictionaryGetValue(peer->session->defaultCredentials, cred->mech->name); 600 if ((defcred == NULL || CFDictionaryGetValue(peer->session->items, defcred) == NULL) 601 && (lead = CFDictionaryGetValue(cred->attributes, kHEIMAttrLeadCredential)) 602 && CFBooleanGetValue(lead)) 603 { 604 CFDictionarySetValue(peer->session->defaultCredentials, cred->mech->name, cred->uuid); 605 } 606 607 HeimCredMessageSetAttributes(reply, "attributes", cred->attributes); 608out: 609 CFRELEASE_NULL(attrs); 610 CFRELEASE_NULL(attributes); 611 CFRELEASE_NULL(cred); 612 CFRELEASE_NULL(uuid); 613 CFRELEASE_NULL(error); 614} 615 616struct MatchCTX { 617 struct peer *peer; 618 CFMutableArrayRef results; 619 CFDictionaryRef query; 620 CFIndex numQueryItems; 621 CFDictionaryRef attributes; 622 CFIndex count; 623}; 624 625static void 626MatchQueryItem(const void *key, const void *value, void *context) 627{ 628 struct MatchCTX * mc = (struct MatchCTX *)context; 629 heim_assert(mc->attributes != NULL, "attributes NULL in MatchQueryItem"); 630 631 /* 632 * Exact matching for each rule, kCFNull matches when key is not set. 633 */ 634 635 CFTypeRef val = CFDictionaryGetValue(mc->attributes, key); 636 if (val == NULL) { 637 if (!CFEqual(kCFNull, value)) 638 return; 639 } else if (!CFEqual(val, value)) 640 return; 641 mc->count++; 642} 643 644static void 645MatchQueryCred(const void *key, const void *value, void *context) 646{ 647 struct MatchCTX *mc = (struct MatchCTX *)context; 648 CFUUIDRef uuid = (CFUUIDRef)key; 649 650 if (!checkACLInCredentialChain(mc->peer, uuid, NULL)) 651 return; 652 653 HeimCredRef cred = (HeimCredRef)value; 654 heim_assert(CFGetTypeID(cred) == HeimCredGetTypeID(), "cred wrong type"); 655 656 if (cred->attributes == NULL) 657 return; 658 mc->attributes = cred->attributes; 659 mc->count = 0; 660 CFDictionaryApplyFunction(mc->query, MatchQueryItem, mc); 661 heim_assert(mc->numQueryItems >= mc->count, "cant have matched more then number of queries"); 662 663 /* found a match */ 664 if (mc->numQueryItems == mc->count) 665 CFArrayAppendValue(mc->results, cred); 666} 667 668static void 669MatchQuerySchema(const void *key, const void *value, void *context) 670{ 671 struct MatchCTX *mc = (struct MatchCTX *)context; 672 673 CFDictionaryRef schema = (CFDictionaryRef)value; 674 heim_assert(CFGetTypeID(schema) == CFDictionaryGetTypeID(), "schema wrong type"); 675 676 mc->attributes = schema; 677 mc->count = 0; 678 CFDictionaryApplyFunction(mc->query, MatchQueryItem, mc); 679 heim_assert(mc->numQueryItems >= mc->count, "cant have matched more then number of queries"); 680 681 /* found a match */ 682 if (mc->numQueryItems == mc->count) 683 CFArrayAppendValue(mc->results, schema); 684} 685 686 687static CFMutableArrayRef 688QueryCopy(struct peer *peer, xpc_object_t request, const char *key) 689{ 690 struct MatchCTX mc = { 691 .peer = peer, 692 .results = NULL, 693 .query = NULL, 694 .attributes = NULL, 695 }; 696 CFUUIDRef uuidref = NULL; 697 CFErrorRef error = NULL; 698 699 mc.query = HeimCredMessageCopyAttributes(request, key, CFDictionaryGetTypeID()); 700 if (mc.query == NULL) 701 goto out; 702 703 mc.numQueryItems = CFDictionaryGetCount(mc.query); 704 705 if (mc.numQueryItems == 1) { 706 uuidref = CFDictionaryGetValue(mc.query, kHEIMAttrUUID); 707 if (uuidref && CFGetTypeID(uuidref) == CFUUIDGetTypeID()) { 708 709 if (!checkACLInCredentialChain(peer, uuidref, NULL)) 710 goto out; 711 712 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(peer->session->items, uuidref); 713 if (cred == NULL) 714 goto out; 715 716 heim_assert(CFGetTypeID(cred) == HeimCredGetTypeID(), "cred wrong type"); 717 718 mc.results = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 719 CFArrayAppendValue(mc.results, cred); 720 721 goto out; 722 } 723 } 724 725 mc.results = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 726 727 CFStringRef type = GetValidatedValue(mc.query, kHEIMAttrType, CFStringGetTypeID(), &error); 728 if (CFEqual(type, kHEIMTypeSchema)) 729 CFDictionaryApplyFunction(HeimCredCTX.schemas, MatchQuerySchema, &mc); 730 else 731 CFDictionaryApplyFunction(peer->session->items, MatchQueryCred, &mc); 732 733out: 734 CFRELEASE_NULL(error); 735 CFRELEASE_NULL(mc.query); 736 return mc.results; 737} 738 739struct child { 740 CFUUIDRef parent; 741 CFMutableArrayRef array; 742 struct HeimSession *session; 743}; 744 745static void 746DeleteChild(const void *key, const void *value, void *context) 747{ 748 struct child *child = (struct child *)context; 749 750 if (CFEqual(key, child->parent)) 751 return; 752 753 HeimCredRef cred = (HeimCredRef)value; 754 heim_assert(CFGetTypeID(cred) == HeimCredGetTypeID(), "cred wrong type"); 755 756 CFUUIDRef parent = CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential); 757 if (parent && CFEqual(child->parent, parent)) { 758 CFArrayAppendValue(child->array, cred->uuid); 759 760 handleDefaultCredentialDeletion(child->session, cred); 761 762 /* 763 * Recurse over grandchildren too 764 */ 765 struct child grandchildren = { 766 .parent = key, 767 .array = child->array, 768 .session = child->session, 769 }; 770 CFDictionaryApplyFunction(child->session->items, DeleteChild, &grandchildren); 771 } 772} 773 774static void 775DeleteChildrenApplier(const void *value, void *context) 776{ 777 struct HeimSession *session = (struct HeimSession *)context; 778 heim_assert(CFGetTypeID(value) == CFUUIDGetTypeID(), "Value not an CFUUIDRef"); 779 CFDictionaryRemoveValue(session->items, value); 780} 781 782 783static void 784DeleteChildren(struct HeimSession *session, CFUUIDRef parent) 785{ 786 /* 787 * delete all child entries for to UUID 788 */ 789 struct child child = { 790 .parent = parent, 791 .array = NULL, 792 .session = session, 793 }; 794 child.array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 795 CFDictionaryApplyFunction(session->items, DeleteChild, &child); 796 CFArrayApplyFunction(child.array, CFRangeMake(0, CFArrayGetCount(child.array)), DeleteChildrenApplier, session); 797 CFRelease(child.array); 798} 799 800struct fromto { 801 CFUUIDRef from; 802 CFUUIDRef to; 803}; 804 805static void 806UpdateParent(const void *key, const void *value, void *context) 807{ 808 struct fromto *fromto = (struct fromto *)context; 809 HeimCredRef cred = (HeimCredRef)value; 810 heim_assert(CFGetTypeID(cred) == HeimCredGetTypeID(), "cred wrong type"); 811 812 CFUUIDRef parent = CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential); 813 if (parent && CFEqual(parent, fromto->from)) { 814 CFMutableDictionaryRef attrs = CFDictionaryCreateMutableCopy(NULL, 0, cred->attributes); 815 CFRelease(cred->attributes); 816 CFDictionarySetValue(attrs, kHEIMAttrParentCredential, fromto->to); 817 cred->attributes = attrs; 818 } 819} 820 821 822 823 824static void 825do_Delete(struct peer *peer, xpc_object_t request, xpc_object_t reply) 826{ 827 CFErrorRef error = NULL; 828 829 CFArrayRef items = QueryCopy(peer, request, "query"); 830 if (items == NULL || CFArrayGetCount(items) == 0) { 831 const void *const keys[] = { CFSTR("CommonErrorCode") }; 832 const void *const values[] = { kCFBooleanTrue }; 833 HCMakeError(&error, kHeimCredErrorNoItemsMatchesQuery, keys, values, 1); 834 goto out; 835 } 836 837 CFIndex n, count = CFArrayGetCount(items); 838 for (n = 0; n < count; n++) { 839 HeimCredRef cred = (HeimCredRef)CFArrayGetValueAtIndex(items, n); 840 heim_assert(CFGetTypeID(cred) == HeimCredGetTypeID(), "cred wrong type"); 841 842 CFDictionaryRemoveValue(peer->session->items, cred->uuid); 843 DeleteChildren(peer->session, cred->uuid); 844 } 845 846 notifyChangedCaches(); 847 HeimCredCTX.needFlush = 1; 848 849 out: 850 if (error) { 851 addErrorToReply(reply, error); 852 CFRelease(error); 853 } 854 CFRELEASE_NULL(items); 855} 856 857static void 858updateCred(const void *key, const void *value, void *context) 859{ 860 CFMutableDictionaryRef attrs = (CFMutableDictionaryRef)context; 861 CFDictionarySetValue(attrs, key, value); 862} 863 864 865static void 866do_SetAttrs(struct peer *peer, xpc_object_t request, xpc_object_t reply) 867{ 868 CFUUIDRef uuid = HeimCredCopyUUID(request, "uuid"); 869 CFMutableDictionaryRef attrs; 870 CFErrorRef error = NULL; 871 872 if (uuid == NULL) 873 return; 874 875 if (!checkACLInCredentialChain(peer, uuid, NULL)) { 876 CFRelease(uuid); 877 return; 878 } 879 880 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(peer->session->items, uuid); 881 CFRelease(uuid); 882 if (cred == NULL) 883 return; 884 885 heim_assert(CFGetTypeID(cred) == HeimCredGetTypeID(), "cred wrong type"); 886 887 if (cred->attributes) { 888 attrs = CFDictionaryCreateMutableCopy(NULL, 0, cred->attributes); 889 if (attrs == NULL) 890 return; 891 } else { 892 attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 893 } 894 895 CFDictionaryRef replacementAttrs = HeimCredMessageCopyAttributes(request, "attributes", CFDictionaryGetTypeID()); 896 if (replacementAttrs == NULL) { 897 CFRelease(attrs); 898 goto out; 899 } 900 901 CFDictionaryApplyFunction(replacementAttrs, updateCred, attrs); 902 CFRELEASE_NULL(replacementAttrs); 903 904 if (!validateObject(attrs, &error)) { 905 addErrorToReply(reply, error); 906 goto out; 907 } 908 909 handleDefaultCredentialUpdate(peer->session, cred, attrs); 910 911 /* make sure the current caller is on the ACL list */ 912 addPeerToACL(peer, attrs); 913 914 CFRELEASE_NULL(cred->attributes); 915 cred->attributes = attrs; 916 out: 917 CFRELEASE_NULL(error); 918} 919 920static void 921do_Fetch(struct peer *peer, xpc_object_t request, xpc_object_t reply) 922{ 923 CFUUIDRef uuid = HeimCredCopyUUID(request, "uuid"); 924 if (uuid == NULL) 925 return; 926 927 if (!checkACLInCredentialChain(peer, uuid, NULL)) { 928 CFRelease(uuid); 929 return; 930 } 931 932 HeimCredRef cred = (HeimCredRef)CFDictionaryGetValue(peer->session->items, uuid); 933 CFRelease(uuid); 934 if (cred == NULL) 935 return; 936 937 /* XXX filter the attributes */ 938 939 HeimCredMessageSetAttributes(reply, "attributes", cred->attributes); 940} 941 942static CFComparisonResult 943orderLeadFirst(const void *val1, const void *val2, void *context) 944{ 945 HeimCredRef cred1 = (HeimCredRef)val1; 946 HeimCredRef cred2 = (HeimCredRef)val2; 947 948 CFTypeRef uuid1 = CFDictionaryGetValue(cred1->attributes, kHEIMAttrParentCredential); 949 CFTypeRef uuid2 = CFDictionaryGetValue(cred2->attributes, kHEIMAttrParentCredential); 950 951 if (uuid1 && uuid2 && CFEqual(uuid1, uuid2)) { 952 CFBooleanRef lead1 = CFDictionaryGetValue(cred1->attributes, kHEIMAttrLeadCredential); 953 CFBooleanRef lead2 = CFDictionaryGetValue(cred2->attributes, kHEIMAttrLeadCredential); 954 955 if (lead1 && CFBooleanGetValue(lead1)) 956 return kCFCompareLessThan; 957 if (lead2 && CFBooleanGetValue(lead2)) 958 return kCFCompareGreaterThan; 959 } 960 961 CFErrorRef error = NULL; 962 963 CFDateRef authTime1 = GetValidatedValue(cred1->attributes, kHEIMAttrStoreTime, CFDateGetTypeID(), &error); 964 CFRELEASE_NULL(error); 965 CFDateRef authTime2 = GetValidatedValue(cred2->attributes, kHEIMAttrStoreTime, CFDateGetTypeID(), &error); 966 CFRELEASE_NULL(error); 967 968 if (authTime1 && authTime2) 969 return CFDateCompare(authTime1, authTime2, NULL); 970 971 CFIndex hash1 = CFHash(cred1->uuid); 972 CFIndex hash2 = CFHash(cred2->uuid); 973 974 if (hash1 < hash2) 975 return kCFCompareLessThan; 976 977 return kCFCompareGreaterThan; 978} 979 980 981static void 982do_Query(struct peer *peer, xpc_object_t request, xpc_object_t reply) 983{ 984 CFMutableArrayRef array = NULL; 985 CFErrorRef error = NULL; 986 987 reElectDefaultCredential(peer); 988 989 CFMutableArrayRef items = QueryCopy(peer, request, "query"); 990 if (items == NULL) { 991 const void *const keys[] = { CFSTR("CommonErrorCode") }; 992 const void *const values[] = { kCFBooleanTrue }; 993 HCMakeError(&error, kHeimCredErrorNoItemsMatchesQuery, keys, values, 1); 994 goto out; 995 } 996 997 array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 998 if (array == NULL) { 999 goto out; 1000 } 1001 1002 CFIndex n, count = CFArrayGetCount(items); 1003 1004 if (count > 1) 1005 CFArraySortValues(items, CFRangeMake(0, count), orderLeadFirst, NULL); 1006 1007 for (n = 0; n < count; n++) { 1008 HeimCredRef cred = (HeimCredRef)CFArrayGetValueAtIndex(items, n); 1009 CFArrayAppendValue(array, cred->uuid); 1010 } 1011 CFRELEASE_NULL(items); 1012 1013 HeimCredMessageSetAttributes(reply, "items", array); 1014 1015 out: 1016 if (error) { 1017 addErrorToReply(reply, error); 1018 CFRelease(error); 1019 } 1020 CFRELEASE_NULL(array); 1021 CFRELEASE_NULL(items); 1022} 1023 1024static void 1025do_GetDefault(struct peer *peer, xpc_object_t request, xpc_object_t reply) 1026{ 1027 CFErrorRef error = NULL; 1028 1029 reElectDefaultCredential(peer); 1030 1031 CFStringRef mechName = HeimCredMessageCopyAttributes(request, "mech", CFStringGetTypeID()); 1032 if (mechName == NULL) { 1033 HCMakeError(&error, kHeimCredErrorNoItemsMatchesQuery, NULL, NULL, 0); 1034 goto out; 1035 } 1036 1037 CFUUIDRef defCred = CFDictionaryGetValue(peer->session->defaultCredentials, mechName); 1038 if (defCred == NULL) { 1039 /* 1040 * If there is is no credential, try to elect one 1041 */ 1042 peer->session->updateDefaultCredential = 1; 1043 reElectDefaultCredential(peer); 1044 1045 defCred = CFDictionaryGetValue(peer->session->defaultCredentials, mechName); 1046 if (defCred == NULL) { 1047 HCMakeError(&error, kHeimCredErrorNoItemsMatchesQuery, NULL, NULL, 0); 1048 goto out; 1049 } 1050 } 1051 1052 HeimCredMessageSetAttributes(reply, "default", defCred); 1053 out: 1054 if (error) { 1055 addErrorToReply(reply, error); 1056 CFRelease(error); 1057 } 1058} 1059 1060static void 1061do_Move(struct peer *peer, xpc_object_t request, xpc_object_t reply) 1062{ 1063 CFUUIDRef from = HeimCredMessageCopyAttributes(request, "from", CFUUIDGetTypeID()); 1064 CFUUIDRef to = HeimCredMessageCopyAttributes(request, "to", CFUUIDGetTypeID()); 1065 1066 if (from == NULL || to == NULL) { 1067 CFRELEASE_NULL(from); 1068 CFRELEASE_NULL(to); 1069 return; 1070 } 1071 1072 if (!checkACLInCredentialChain(peer, from, NULL) || !checkACLInCredentialChain(peer, to, NULL)) { 1073 CFRelease(from); 1074 CFRelease(to); 1075 return; 1076 } 1077 1078 HeimCredRef credfrom = (HeimCredRef)CFDictionaryGetValue(peer->session->items, from); 1079 HeimCredRef credto = (HeimCredRef)CFDictionaryGetValue(peer->session->items, to); 1080 1081 if (credfrom == NULL) { 1082 CFRelease(from); 1083 CFRelease(to); 1084 return; 1085 } 1086 1087 1088 CFMutableDictionaryRef newattrs = CFDictionaryCreateMutableCopy(NULL, 0, credfrom->attributes); 1089 CFDictionaryRemoveValue(peer->session->items, from); 1090 credfrom = NULL; 1091 1092 CFDictionarySetValue(newattrs, kHEIMAttrUUID, to); 1093 1094 if (credto == NULL) { 1095 credto = HeimCredCreateItem(to); 1096 heim_assert(credto != NULL, "out of memory"); 1097 1098 HeimCredAssignMech(credto, newattrs); 1099 1100 credto->attributes = newattrs; 1101 CFDictionarySetValue(peer->session->items, credto->uuid, credto); 1102 CFRelease(credto); 1103 1104 } else { 1105 CFUUIDRef parentUUID = CFDictionaryGetValue(credto->attributes, kHEIMAttrParentCredential); 1106 if (parentUUID) 1107 CFDictionarySetValue(newattrs, kHEIMAttrParentCredential, parentUUID); 1108 CFRELEASE_NULL(credto->attributes); 1109 credto->attributes = newattrs; 1110 } 1111 1112 /* 1113 * delete all child entries for to UUID 1114 */ 1115 DeleteChildren(peer->session, to); 1116 1117 /* 1118 * update all child entries for from UUID 1119 */ 1120 struct fromto fromto = { 1121 .from = from, 1122 .to = to, 1123 }; 1124 CFDictionaryApplyFunction(peer->session->items, UpdateParent, &fromto); 1125 1126 notifyChangedCaches(); 1127 HeimCredCTX.needFlush = 1; 1128} 1129 1130static void 1131StatusCredential(const void *key, const void *value, void *context) 1132{ 1133 HeimCredRef cred = (HeimCredRef)value; 1134 xpc_object_t sc = (xpc_object_t)context; 1135 char *s; 1136 1137 if (CFDictionaryGetValue(cred->attributes, kHEIMAttrParentCredential) != NULL) 1138 return; 1139 1140 xpc_object_t xc = xpc_dictionary_create(NULL, NULL, 0); 1141 1142 CFStringRef us = CFUUIDCreateString(NULL, cred->uuid); 1143 s = rk_cfstring2cstring(us); 1144 CFRelease(us); 1145 1146 xpc_dictionary_set_value(sc, s, xc); 1147 xpc_release(xc); 1148 free(s); 1149 1150 CFStringRef name = CFDictionaryGetValue(cred->attributes, kHEIMAttrClientName); 1151 if (name) { 1152 s = rk_cfstring2cstring(name); 1153 xpc_dictionary_set_string(xc, "name", s); 1154 free(s); 1155 } 1156 1157 s = rk_cfstring2cstring(cred->mech->name); 1158 xpc_dictionary_set_string(xc, "mech", s); 1159 free(s); 1160} 1161 1162static void 1163StatusSession(const void *key, const void *value, void *context) 1164{ 1165 struct HeimSession *session = (struct HeimSession *)value; 1166 xpc_object_t ss = (xpc_object_t)context; 1167 xpc_object_t sc = xpc_dictionary_create(NULL, NULL, 0); 1168 CFDictionaryApplyFunction(session->items, StatusCredential, sc); 1169 CFStringRef sessionID = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), key); 1170 char *s = rk_cfstring2cstring(sessionID); 1171 xpc_dictionary_set_value(ss, s, sc); 1172 free(s); 1173 xpc_release(sc); 1174 CFRelease(sessionID); 1175} 1176 1177static void 1178do_Status(struct peer *peer, xpc_object_t request, xpc_object_t reply) 1179{ 1180 uid_t uid = xpc_connection_get_euid(peer->peer); 1181 struct stat sb; 1182 1183 if (uid == 0) { 1184 xpc_object_t ss = xpc_dictionary_create(NULL, NULL, 0); 1185 1186 CFDictionaryApplyFunction(HeimCredCTX.sessions, StatusSession, ss); 1187 xpc_dictionary_set_value(reply, "items", ss); 1188 xpc_release(ss); 1189 } 1190 1191 if (stat([archivePath UTF8String], &sb) == 0) { 1192 xpc_dictionary_set_int64(reply, "cache-size", (int64_t)sb.st_size); 1193 } else { 1194 xpc_dictionary_set_int64(reply, "cache-size", 0); 1195 } 1196} 1197 1198static void GSSCred_peer_event_handler(struct peer *peer, xpc_object_t event) 1199{ 1200 xpc_object_t reply = NULL; 1201 xpc_type_t type = xpc_get_type(event); 1202 if (type == XPC_TYPE_ERROR) 1203 return; 1204 1205 assert(type == XPC_TYPE_DICTIONARY); 1206 1207 const char *cmd = xpc_dictionary_get_string(event, "command"); 1208 if (cmd == NULL) { 1209 syslog(LOG_ERR, "peer sent invalid no command"); 1210 xpc_connection_cancel(peer->peer); 1211 } else if (strcmp(cmd, "wakeup") == 0) { 1212 1213 } else if (strcmp(cmd, "create") == 0) { 1214 reply = xpc_dictionary_create_reply(event); 1215 do_CreateCred(peer, event, reply); 1216 } else if (strcmp(cmd, "delete") == 0) { 1217 reply = xpc_dictionary_create_reply(event); 1218 do_Delete(peer, event, reply); 1219 } else if (strcmp(cmd, "setattributes") == 0) { 1220 reply = xpc_dictionary_create_reply(event); 1221 do_SetAttrs(peer, event, reply); 1222 } else if (strcmp(cmd, "fetch") == 0) { 1223 reply = xpc_dictionary_create_reply(event); 1224 do_Fetch(peer, event, reply); 1225 } else if (strcmp(cmd, "move") == 0) { 1226 reply = xpc_dictionary_create_reply(event); 1227 do_Move(peer, event, reply); 1228 } else if (strcmp(cmd, "query") == 0) { 1229 reply = xpc_dictionary_create_reply(event); 1230 do_Query(peer, event, reply); 1231 } else if (strcmp(cmd, "default") == 0) { 1232 reply = xpc_dictionary_create_reply(event); 1233 do_GetDefault(peer, event, reply); 1234 } else if (strcmp(cmd, "retain-transient") == 0) { 1235 reply = xpc_dictionary_create_reply(event); 1236 } else if (strcmp(cmd, "release-transient") == 0) { 1237 reply = xpc_dictionary_create_reply(event); 1238 } else if (strcmp(cmd, "status") == 0) { 1239 reply = xpc_dictionary_create_reply(event); 1240 do_Status(peer, event, reply); 1241 } else { 1242 syslog(LOG_ERR, "peer sent invalid command %s", cmd); 1243 xpc_connection_cancel(peer->peer); 1244 } 1245 1246 if (reply) { 1247 xpc_connection_send_message(peer->peer, reply); 1248 xpc_release(reply); 1249 } 1250 1251 if (HeimCredCTX.needFlush) { 1252 if (!HeimCredCTX.flushPending) { 1253 HeimCredCTX.needFlush = false; 1254 } else { 1255 HeimCredCTX.flushPending = true; 1256 1257 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5LL * NSEC_PER_SEC), runQueue, ^{ 1258 @autoreleasepool { 1259 HeimCredCTX.flushPending = false; 1260 storeCredCache(); 1261 } 1262 }); 1263 } 1264 } 1265} 1266 1267static void 1268peer_final(void *ptr) 1269{ 1270 struct peer *peer = ptr; 1271 CFRELEASE_NULL(peer->bundleID); 1272 CFRELEASE_NULL(peer->session); 1273} 1274 1275static CFStringRef 1276CopySigningIdentitier(xpc_connection_t conn) 1277{ 1278#if TARGET_IPHONE_SIMULATOR 1279 char path[MAXPATHLEN]; 1280 CFStringRef ident = NULL; 1281 const char *str = NULL; 1282 1283 /* simulator binaries are not codesigned, fake it */ 1284 if (proc_pidpath(getpid(), path, sizeof(path)) > 0) { 1285 xpc_bundle_t bundle = xpc_bundle_create(path, XPC_BUNDLE_FROM_PATH); 1286 if (bundle) { 1287 xpc_object_t xdict = xpc_bundle_get_info_dictionary(bundle); 1288 if (xdict) { 1289 str = xpc_dictionary_get_string(xdict, "CFBundleIdentifier"); 1290 if (str) 1291 ident = CFStringCreateWithFormat(NULL, NULL, CFSTR("%s"), str); 1292 } 1293 xpc_release(bundle); 1294 } 1295 /* 1296 * If not a bundle, its a command line tool, lets use com.apple.$(basename) 1297 */ 1298 if (ident == NULL) { 1299 str = strrchr(path, '/'); 1300 if (str) { 1301 str++; 1302 ident = CFStringCreateWithFormat(NULL, NULL, CFSTR("com.apple.%s"), str); 1303 } 1304 } 1305 } 1306 if (ident == NULL) 1307 ident = CFSTR("iphonesimulator"); 1308 return ident; 1309#else 1310 CFStringRef res; 1311 uint8_t header[8] = { 0 }; 1312 uint32_t len; 1313 audit_token_t audit_token; 1314 pid_t pid; 1315 1316 pid = xpc_connection_get_pid(conn); 1317 xpc_connection_get_audit_token(conn, &audit_token); 1318 1319 int rcent = csops_audittoken(pid, CS_OPS_IDENTITY, header, sizeof(header), &audit_token); 1320 if (rcent != -1 || errno != ERANGE) 1321 return NULL; 1322 1323 memcpy(&len, &header[4], 4); 1324 len = ntohl(len); 1325 if (len > 1024 * 1024) 1326 return NULL; 1327 else if (len == 0) 1328 return NULL; 1329 1330 uint8_t *buffer = malloc(len); 1331 if (buffer == NULL) 1332 return NULL; 1333 1334 rcent = csops_audittoken(pid, CS_OPS_IDENTITY, buffer, len, &audit_token); 1335 if (rcent != 0) { 1336 free(buffer); 1337 return NULL; 1338 } 1339 1340 char *p = (char *)buffer; 1341 if (len > 8) { 1342 p += 8; 1343 len -= 8; 1344 } else 1345 return NULL; 1346 1347 if (p[len - 1] != '\0') { 1348 free(buffer); 1349 return NULL; 1350 } 1351 1352 res = CFStringCreateWithBytes(NULL, (UInt8 *)p, len - 1, kCFStringEncodingUTF8, false); 1353 free(buffer); 1354 return res; 1355#endif 1356} 1357 1358/* 1359 * 1360 */ 1361 1362static struct HeimSession * 1363HeimCredCopySession(int sessionID) 1364{ 1365 struct HeimSession *session; 1366 CFNumberRef sid; 1367 1368 sid = CFNumberCreate(NULL, kCFNumberIntType, &sessionID); 1369 heim_assert(sid != NULL, "out of memory"); 1370 1371 1372 session = (struct HeimSession *)CFDictionaryGetValue(HeimCredCTX.sessions, sid); 1373 if (session) { 1374 CFRelease(sid); 1375 CFRetain(session); 1376 return session; 1377 } 1378 1379 CFTypeID sessionTID = getSessionTypeID(); 1380 1381 heim_assert(sessionTID != _kCFRuntimeNotATypeID, "could not register cftype"); 1382 1383 session = (struct HeimSession *)_CFRuntimeCreateInstance(NULL, sessionTID, sizeof(struct HeimSession) - sizeof(CFRuntimeBase), NULL); 1384 heim_assert(session != NULL, "out of memory while registering HeimMech instance"); 1385 1386 session->session = sessionID; 1387 session->items = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1388 session->defaultCredentials = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1389 session->updateDefaultCredential = 0; 1390 1391 CFDictionarySetValue(HeimCredCTX.sessions, sid, session); 1392 CFRelease(sid); 1393 1394 return session; 1395} 1396 1397/* 1398 * 1399 */ 1400 1401static void GSSCred_event_handler(xpc_connection_t peerconn) 1402{ 1403 struct peer *peer; 1404 1405 peer = malloc(sizeof(*peer)); 1406 heim_assert(peer != NULL, "out of memory"); 1407 1408 peer->peer = peerconn; 1409 peer->bundleID = CopySigningIdentitier(peerconn); 1410 if (peer->bundleID == NULL) { 1411 char path[MAXPATHLEN]; 1412 1413 if (proc_pidpath(getpid(), path, sizeof(path)) <= 0) 1414 path[0] = '\0'; 1415 1416 syslog(LOG_ERR, "client[pid-%d] \"%s\" is not signed", (int)xpc_connection_get_pid(peerconn), path); 1417#if TARGET_OS_EMBEDDED 1418 free(peer); 1419 xpc_connection_cancel(peerconn); 1420 return; 1421#else 1422 peer->bundleID = CFStringCreateWithFormat(NULL, NULL, CFSTR("unsigned-binary-path:%s-end"), path); 1423 heim_assert(peer->bundleID != NULL, "out of memory"); 1424#endif 1425 } 1426 peer->session = HeimCredCopySession(xpc_connection_get_asid(peerconn)); 1427 heim_assert(peer->session != NULL, "out of memory"); 1428 1429 xpc_connection_set_context(peerconn, peer); 1430 xpc_connection_set_finalizer_f(peerconn, peer_final); 1431 1432 xpc_connection_set_event_handler(peerconn, ^(xpc_object_t event) { 1433 GSSCred_peer_event_handler(peer, event); 1434 }); 1435 xpc_connection_resume(peerconn); 1436} 1437 1438static void 1439addErrorToReply(xpc_object_t reply, CFErrorRef error) 1440{ 1441 if (error == NULL) 1442 return; 1443 1444 xpc_object_t xe = xpc_dictionary_create(NULL, NULL, 0); 1445 xpc_dictionary_set_int64(xe, "error-code", CFErrorGetCode(error)); 1446 xpc_dictionary_set_value(reply, "error", xe); 1447 xpc_release(xe); 1448} 1449 1450/* 1451 * 1452 */ 1453 1454static CFStringRef 1455debug_session(CFTypeRef cf) 1456{ 1457 return CFSTR("debugsession"); 1458} 1459 1460static void 1461release_session(CFTypeRef cf) 1462{ 1463 struct HeimSession *session = (struct HeimSession *)cf; 1464 CFRELEASE_NULL(session->items); 1465 CFRELEASE_NULL(session->defaultCredentials); 1466} 1467 1468static CFTypeID 1469getSessionTypeID(void) 1470{ 1471 static CFTypeID haid = _kCFRuntimeNotATypeID; 1472 static dispatch_once_t inited; 1473 1474 dispatch_once(&inited, ^{ 1475 static const CFRuntimeClass HeimCredSessionClass = { 1476 0, 1477 "HeimCredSession", 1478 NULL, 1479 NULL, 1480 release_session, 1481 NULL, 1482 NULL, 1483 NULL, 1484 debug_session 1485 }; 1486 haid = _CFRuntimeRegisterClass(&HeimCredSessionClass); 1487 }); 1488 return haid; 1489} 1490 1491/* 1492 * 1493 */ 1494 1495static CFStringRef 1496debug_mech(CFTypeRef cf) 1497{ 1498 return CFSTR("debugmech"); 1499} 1500 1501static void 1502release_mech(CFTypeRef cf) 1503{ 1504 struct HeimMech *mech = (struct HeimMech *)cf; 1505 CFRELEASE_NULL(mech->name); 1506} 1507 1508static CFTypeID 1509getMechTypeID(void) 1510{ 1511 static CFTypeID haid = _kCFRuntimeNotATypeID; 1512 static dispatch_once_t inited; 1513 1514 dispatch_once(&inited, ^{ 1515 static const CFRuntimeClass HeimCredMechanismClass = { 1516 0, 1517 "HeimCredMechanism", 1518 NULL, 1519 NULL, 1520 release_mech, 1521 NULL, 1522 NULL, 1523 NULL, 1524 debug_mech 1525 }; 1526 haid = _CFRuntimeRegisterClass(&HeimCredMechanismClass); 1527 }); 1528 return haid; 1529} 1530 1531/* 1532 * 1533 */ 1534 1535static CFTypeRef 1536GetValidatedValue(CFDictionaryRef object, CFStringRef key, CFTypeID requiredTypeID, CFErrorRef *error) 1537{ 1538 heim_assert(error != NULL, "error ptr required"); 1539 1540 CFTypeRef value = CFDictionaryGetValue(object, key); 1541 if (value == NULL) 1542 return NULL; 1543 if (CFGetTypeID(value) != requiredTypeID) 1544 return NULL; 1545 return value; 1546} 1547 1548struct validate { 1549 CFDictionaryRef schema; 1550 CFDictionaryRef object; 1551 CFTypeID subTypeID; 1552 CFErrorRef *error; 1553 bool valid; 1554}; 1555 1556#define kHeimCredErrorDomain CFSTR("com.apple.GSS.credential-store") 1557 1558static void 1559HCMakeError(CFErrorRef *error, CFIndex code, 1560 const void *const *keys, 1561 const void *const *values, 1562 CFIndex num) 1563{ 1564 if (*error != NULL) 1565 return; 1566 *error = CFErrorCreateWithUserInfoKeysAndValues(NULL, kHeimCredErrorDomain, code, keys, values, num); 1567} 1568 1569static void 1570ValidateKey(const void *key, const void *value, void *context) 1571{ 1572 struct validate *ctx = (struct validate *)context; 1573 CFStringRef rule; 1574 1575 rule = GetValidatedValue(ctx->schema, key, CFStringGetTypeID(), ctx->error); 1576 if (rule == NULL) { 1577 const void *const keys[] = { CFSTR("Key"), CFSTR("CommonErrorCode") }; 1578 const void *const values[] = { key, kCFBooleanTrue }; 1579 HCMakeError(ctx->error, kHeimCredErrorUnknownKey, keys, values, 2); 1580 ctx->valid = false; 1581 syslog(LOG_ERR, "unknown key"); 1582 return; 1583 } 1584 1585 return; 1586} 1587 1588static bool 1589StringContains(CFStringRef haystack, CFStringRef needle) 1590{ 1591 if (CFStringFind(haystack, needle, 0).location == kCFNotFound) 1592 return false; 1593 return true; 1594} 1595 1596static CFTypeID 1597GetTypeFromSchemaRule(CFStringRef key, CFStringRef rule, bool typeLevelType) 1598{ 1599 if (typeLevelType && StringContains(rule, CFSTR("a"))) 1600 return CFArrayGetTypeID(); 1601 else if (StringContains(rule, CFSTR("s"))) 1602 return CFStringGetTypeID(); 1603 else if (StringContains(rule, CFSTR("u"))) 1604 return CFUUIDGetTypeID(); 1605 else if (StringContains(rule, CFSTR("d"))) 1606 return CFDataGetTypeID(); 1607 else if (StringContains(rule, CFSTR("b"))) 1608 return CFBooleanGetTypeID(); 1609 else if (StringContains(rule, CFSTR("t"))) 1610 return CFDateGetTypeID(); 1611 else if (StringContains(rule, CFSTR("n"))) 1612 return CFNumberGetTypeID(); 1613 1614 heim_abort("key %s have a broken rule %s", rk_cfstring2cstring(rule), rk_cfstring2cstring(key)); 1615} 1616 1617static void 1618ValidateSubtype(const void *value, void *context) 1619{ 1620 struct validate *ctx = (struct validate *)context; 1621 if (CFGetTypeID(value) != ctx->subTypeID) { 1622 const void *const keys[] = { CFSTR("CommonErrorCode") }; 1623 const void *const values[] = { kCFBooleanTrue }; 1624 HCMakeError(ctx->error, kHeimCredErrorUnknownKey, keys, values, 1); 1625 ctx->valid = false; 1626 } 1627} 1628 1629static void 1630ValidateSchema(const void *key, const void *value, void *context) 1631{ 1632 struct validate *ctx = (struct validate *)context; 1633 CFStringRef rule = value; 1634 CFTypeRef ov; 1635 1636 if (CFEqual(kHEIMObjectType, key)) 1637 return; 1638 1639 ov = CFDictionaryGetValue(ctx->object, key); 1640 if (ov == NULL) { 1641 if (StringContains(rule, CFSTR("R"))) { 1642 const void *const keys[] = { CFSTR("Key"), CFSTR("Rule"), CFSTR("CommonErrorCode") }; 1643 const void *const values[] = { key, rule, kCFBooleanTrue }; 1644 HCMakeError(ctx->error, kHeimCredErrorMissingSchemaKey, keys, values, 3); 1645 ctx->valid = false; 1646 syslog(LOG_ERR, "key missing key"); 1647 } 1648 } else { 1649 CFTypeID expectedType = GetTypeFromSchemaRule(key, rule, true); 1650 1651 if (expectedType != CFGetTypeID(ov)) { 1652 const void *const keys[] = { CFSTR("Key"), CFSTR("Rule"), CFSTR("CommonErrorCode") }; 1653 const void *const values[] = { key, rule, kCFBooleanTrue }; 1654 HCMakeError(ctx->error, kHeimCredErrorMissingSchemaKey, keys, values, 3); 1655 ctx->valid = false; 1656 syslog(LOG_ERR, "key have wrong type key"); 1657 } 1658 if (expectedType == CFArrayGetTypeID()) { 1659 ctx->subTypeID = GetTypeFromSchemaRule(key, rule, false); 1660 CFArrayApplyFunction(ov, CFRangeMake(0, CFArrayGetCount(ov)), ValidateSubtype, ctx); 1661 } 1662 } 1663} 1664 1665static bool 1666validateObject(CFDictionaryRef object, CFErrorRef *error) 1667{ 1668 heim_assert(error != NULL, "why you bother validating if you wont report the error to the user"); 1669 1670 struct validate ctx = { 1671 .object = object, 1672 .valid = true, 1673 .error = error 1674 }; 1675 1676 CFStringRef type = GetValidatedValue(object, kHEIMObjectType, CFStringGetTypeID(), error); 1677 if (type == NULL) { 1678 const void *const keys[] = { CFSTR("CommonErrorCode") }; 1679 const void *const values[] = { kCFBooleanTrue }; 1680 HCMakeError(error, kHeimCredErrorMissingSchemaKey, keys, values, 1); 1681 return false; 1682 } 1683 1684 ctx.schema = GetValidatedValue(HeimCredCTX.schemas, type, CFDictionaryGetTypeID(), error); 1685 if (ctx.schema == NULL) { 1686 const void *const keys[] = { CFSTR("CommonErrorCode") }; 1687 const void *const values[] = { kCFBooleanTrue }; 1688 HCMakeError(error, kHeimCredErrorNoSuchSchema, keys, values, 1); 1689 return false; 1690 } 1691 1692 /* XXX validate with schema to see that all required attributes are applied */ 1693 1694 CFDictionaryApplyFunction(object, ValidateKey, &ctx); 1695 CFDictionaryApplyFunction(ctx.schema, ValidateSchema, &ctx); 1696 1697 return ctx.valid; 1698} 1699 1700static void 1701ValidateSchemaAtRegistration(const void *key, const void *value, void *context) 1702{ 1703 if (CFEqual(kHEIMObjectType, key)) 1704 return; 1705 1706 CFTypeID schemaID = GetTypeFromSchemaRule(key, value, true); /* will abort if rule is broken */ 1707 1708 CFStringRef globalValue = CFDictionaryGetValue(HeimCredCTX.globalSchema, key); 1709 if (globalValue == NULL) { 1710 CFDictionarySetValue(HeimCredCTX.globalSchema, key, value); 1711 } else { 1712 CFTypeID globalID = GetTypeFromSchemaRule(key, globalValue, true); 1713 if (globalID != schemaID) { 1714 heim_abort("two schemas have different type for the same key %d != %d (%s)", (int)globalID, (int)schemaID, rk_cfstring2cstring(key)); 1715 } 1716 } 1717} 1718 1719static void 1720registerSchema(const void *value, void *context) 1721{ 1722 CFDictionaryRef schema = (CFDictionaryRef)value; 1723 CFStringRef typeName = CFDictionaryGetValue(schema, kHEIMObjectType); 1724 CFTypeRef other; 1725 1726 heim_assert(typeName != NULL, "schema w/o kHEIMObjectType ?"); 1727 1728 other = CFDictionaryGetValue(HeimCredCTX.schemas, typeName); 1729 heim_assert(other == NULL, "schema already registered"); 1730 1731 CFDictionaryApplyFunction(schema, ValidateSchemaAtRegistration, NULL); 1732 1733 CFDictionarySetValue(HeimCredCTX.schemas, typeName, schema); 1734} 1735 1736void 1737_HeimCredRegisterMech(CFStringRef name, 1738 CFSetRef schemas, 1739 HeimCredStatusCallback statusCallback, 1740 HeimCredAuthCallback authCallback) 1741{ 1742 struct HeimMech *mech; 1743 1744 mech = (struct HeimMech *)CFDictionaryGetValue(HeimCredCTX.mechanisms, name); 1745 heim_assert(mech == NULL, "mech already registered"); 1746 1747 CFTypeID mechID = getMechTypeID(); 1748 1749 heim_assert(mechID != _kCFRuntimeNotATypeID, "could not register cftype"); 1750 1751 mech = (struct HeimMech *)_CFRuntimeCreateInstance(NULL, mechID, sizeof(struct HeimMech) - sizeof(CFRuntimeBase), NULL); 1752 heim_assert(mech != NULL, "out of memory while registering HeimMech instance"); 1753 1754 mech->name = CFRetain(name); 1755 mech->statusCallback = statusCallback; 1756 mech->authCallback = authCallback; 1757 1758 CFDictionarySetValue(HeimCredCTX.mechanisms, name, mech); 1759 1760 CFSetApplyFunction(schemas, registerSchema, NULL); 1761} 1762 1763/* 1764 * schema rules: 1765 * R - required 1766 * G - generate 1767 * s - string 1768 * ax - array of x 1769 * u - uuid 1770 * d - data 1771 * b - boolean 1772 * t - time/date 1773 * 1774 */ 1775 1776 1777CFMutableDictionaryRef 1778_HeimCredCreateBaseSchema(CFStringRef objectType) 1779{ 1780 CFMutableDictionaryRef schema = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1781 1782 CFDictionarySetValue(schema, kHEIMAttrType, kHEIMTypeSchema); 1783 CFDictionarySetValue(schema, kHEIMObjectType, objectType); 1784 CFDictionarySetValue(schema, kHEIMAttrType, CFSTR("Rs")); 1785 CFDictionarySetValue(schema, kHEIMAttrClientName, CFSTR("s")); 1786 CFDictionarySetValue(schema, kHEIMAttrServerName, CFSTR("s")); 1787 CFDictionarySetValue(schema, kHEIMAttrUUID, CFSTR("Gu")); 1788 CFDictionarySetValue(schema, kHEIMAttrDisplayName, CFSTR("s")); 1789 CFDictionarySetValue(schema, kHEIMAttrCredential, CFSTR("b")); 1790 CFDictionarySetValue(schema, kHEIMAttrLeadCredential, CFSTR("b")); 1791 CFDictionarySetValue(schema, kHEIMAttrParentCredential, CFSTR("u")); 1792 CFDictionarySetValue(schema, kHEIMAttrBundleIdentifierACL, CFSTR("as")); 1793 CFDictionarySetValue(schema, kHEIMAttrDefaultCredential, CFSTR("b")); 1794 CFDictionarySetValue(schema, kHEIMAttrAuthTime, CFSTR("t")); 1795 CFDictionarySetValue(schema, kHEIMAttrStoreTime, CFSTR("Gt")); 1796 CFDictionarySetValue(schema, kHEIMAttrData, CFSTR("d")); 1797 CFDictionarySetValue(schema, kHEIMAttrRetainStatus, CFSTR("n")); 1798 1799#if 0 1800 CFDictionarySetValue(schema, kHEIMAttrTransient, CFSTR("b")); 1801 CFDictionarySetValue(schema, kHEIMAttrAllowedDomain, CFSTR("as")); 1802 CFDictionarySetValue(schema, kHEIMAttrStatus, CFSTR("")); 1803 CFDictionarySetValue(schema, kHEIMAttrExpire, CFSTR("t")); 1804 CFDictionarySetValue(schema, kHEIMAttrRenewTill, CFSTR("t")); 1805#endif 1806 1807 return schema; 1808} 1809 1810static void 1811_HeimCredRegisterGeneric(void) 1812{ 1813 CFMutableSetRef set; 1814 CFMutableDictionaryRef schema; 1815 1816 set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 1817 schema = _HeimCredCreateBaseSchema(kHEIMObjectGeneric); 1818 1819 CFSetAddValue(set, schema); 1820 CFRelease(schema); 1821 _HeimCredRegisterMech(kHEIMTypeGeneric, set, NULL, NULL); 1822 CFRelease(set); 1823} 1824 1825static void 1826_HeimCredRegisterConfiguration(void) 1827{ 1828 CFMutableSetRef set; 1829 CFMutableDictionaryRef schema; 1830 1831 set = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); 1832 schema = _HeimCredCreateBaseSchema(kHEIMObjectConfiguration); 1833 1834 CFSetAddValue(set, schema); 1835 CFRelease(schema); 1836 _HeimCredRegisterMech(kHEIMTypeConfiguration, set, NULL, NULL); 1837 CFRelease(set); 1838} 1839 1840#if !TARGET_OS_IPHONE 1841/* 1842 * 1843 */ 1844 1845static void GSSCred_session_handler(xpc_connection_t peerconn) 1846{ 1847 audit_token_t token; 1848 uid_t uid; 1849 1850 xpc_connection_get_audit_token(peerconn, &token); 1851 uid = xpc_connection_get_euid(peerconn); 1852 1853 if (HeimCredCTX.session != xpc_connection_get_asid(peerconn) && uid != 0) { 1854 syslog(LOG_ERR, "client[pid-%d] is not in same session or root", (int)xpc_connection_get_pid(peerconn)); 1855 xpc_connection_cancel(peerconn); 1856 return; 1857 } 1858 1859 /* acquire credential here */ 1860 1861 xpc_connection_cancel(peerconn); 1862} 1863#endif 1864 1865/* 1866 * We don't need to hold a xpc_transaction over this session, since if 1867 * we get killed in the middle of deleting credentials, we'll catch 1868 * that when we start up again. 1869 */ 1870 1871static void 1872SessionMonitor(void) 1873{ 1874 au_sdev_handle_t *h; 1875 dispatch_queue_t bgq; 1876 1877 h = au_sdev_open(AU_SDEVF_ALLSESSIONS); 1878 if (h == NULL) 1879 return; 1880 1881 bgq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); 1882 1883 dispatch_async(bgq, ^{ 1884 for (;;) { 1885 auditinfo_addr_t aio; 1886 int event; 1887 1888 if (au_sdev_read_aia(h, &event, &aio) != 0) 1889 continue; 1890 1891 /* 1892 * Ignore everything but END. This should relly be 1893 * CLOSE but since that is delayed until the credential 1894 * is reused, we can't do that 1895 * */ 1896 if (event != AUE_SESSION_END) 1897 continue; 1898 1899 dispatch_async(dispatch_get_main_queue(), ^{ 1900 int sessionID = aio.ai_asid; 1901 CFNumberRef sid = CFNumberCreate(NULL, kCFNumberIntType, &sessionID); 1902 heim_assert(sid != NULL, "out of memory"); 1903 CFDictionaryRemoveValue(HeimCredCTX.sessions, sid); 1904 CFRelease(sid); 1905 }); 1906 } 1907 }); 1908} 1909 1910 1911/* 1912 * 1913 */ 1914 1915int main(int argc, const char *argv[]) 1916{ 1917 xpc_connection_t conn; 1918 1919#if TARGET_OS_EMBEDDED 1920 char *error = NULL; 1921 1922 if (sandbox_init("com.apple.GSSCred", SANDBOX_NAMED, &error)) { 1923 syslog(LOG_ERR, "failed to enter sandbox: %s", error); 1924 exit(EXIT_FAILURE); 1925 } 1926#endif 1927 1928 HeimCredCTX.mechanisms = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1929 heim_assert(HeimCredCTX.mechanisms != NULL, "out of memory"); 1930 1931 HeimCredCTX.schemas = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1932 heim_assert(HeimCredCTX.schemas != NULL, "out of memory"); 1933 1934 HeimCredCTX.globalSchema = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1935 heim_assert(HeimCredCTX.globalSchema != NULL, "out of memory"); 1936 1937 _HeimCredRegisterGeneric(); 1938 _HeimCredRegisterConfiguration(); 1939 _HeimCredRegisterKerberos(); 1940 _HeimCredRegisterNTLM(); 1941 1942 CFRELEASE_NULL(HeimCredCTX.globalSchema); 1943 1944#if TARGET_IPHONE_SIMULATOR 1945 archivePath = [[NSString alloc] initWithFormat:@"%@/Library/Caches/com.apple.GSSCred.simulator-archive", NSHomeDirectory()]; 1946#else 1947 archivePath = @"/var/db/heim-credential-store.archive"; 1948#endif 1949 1950#if !TARGET_OS_IPHONE 1951 char *instanceId = getenv(LAUNCH_ENV_INSTANCEID); 1952 if (instanceId) { 1953 /* 1954 * Pull out uuid and session stored in the sessionUUID 1955 */ 1956 1957 uuid_t sessionUUID; 1958 if (uuid_parse(instanceId, (void *)&sessionUUID) != 0) { 1959 syslog(LOG_ERR, "can't parse LAUNCH_ENV_INSTANCEID as a uuid"); 1960 return 2; 1961 } 1962 1963 uid_t auid; 1964 memcpy(&auid, &sessionUUID, sizeof(auid)); 1965 1966 HeimCredCTX.session = ntohl(auid); 1967 1968 if (HeimCredCTX.session == 0) { 1969 syslog(LOG_ERR, "0 is not a valid session"); 1970 return 3; 1971 } 1972 1973 /* 1974 * Join that session 1975 */ 1976 mach_port_name_t session_port; 1977 int ret = audit_session_port(HeimCredCTX.session, &session_port); 1978 if (ret) { 1979 syslog(LOG_ERR, "could not get audit session port for %d: %s", HeimCredCTX.session, strerror(errno)); 1980 return 4; 1981 } 1982 audit_session_join(session_port); 1983 mach_port_deallocate(current_task(), session_port); 1984 1985 1986 conn = xpc_connection_create_mach_service("com.apple.GSSCred", 1987 dispatch_get_main_queue(), 1988 XPC_CONNECTION_MACH_SERVICE_LISTENER); 1989 1990 xpc_connection_set_event_handler(conn, ^(xpc_object_t object){ 1991 GSSCred_session_handler(object); 1992 }); 1993 1994 } else 1995#endif 1996 { 1997 1998 _HeimCredInitCommon(); 1999 SessionMonitor(); 2000 readCredCache(); 2001 2002 runQueue = dispatch_queue_create("com.apple.GSSCred", DISPATCH_QUEUE_SERIAL); 2003 heim_assert(runQueue != NULL, "dispatch_queue_create failed"); 2004 2005 conn = xpc_connection_create_mach_service("com.apple.GSSCred", 2006 runQueue, 2007 XPC_CONNECTION_MACH_SERVICE_LISTENER); 2008 2009 xpc_connection_set_event_handler(conn, ^(xpc_object_t object){ 2010 GSSCred_event_handler(object); 2011 }); 2012 2013 } 2014 2015 xpc_connection_resume(conn); 2016 2017 dispatch_main(); 2018} 2019