]> git.saurik.com Git - apple/security.git/blobdiff - Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c
Security-57336.1.9.tar.gz
[apple/security.git] / Security / sec / SOSCircle / SecureObjectSync / SOSAccount.c
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c
deleted file mode 100644 (file)
index 9b1bfdf..0000000
+++ /dev/null
@@ -1,1035 +0,0 @@
-/*
- * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
- */
-
-/*
- * SOSAccount.c -  Implementation of the secure object syncing account.
- * An account contains a SOSCircle for each protection domain synced.
- */
-
-#include "SOSAccountPriv.h"
-#include <SecureObjectSync/SOSPeerInfoCollections.h>
-#include <SecureObjectSync/SOSTransportCircle.h>
-#include <SecureObjectSync/SOSTransportMessage.h>
-#include <SecureObjectSync/SOSKVSKeys.h>
-#include <SecureObjectSync/SOSTransportKeyParameter.h>
-#include <SecureObjectSync/SOSTransportKeyParameterKVS.h>
-#include <SecureObjectSync/SOSEngine.h>
-#include <SecureObjectSync/SOSPeerCoder.h>
-
-CFGiblisWithCompareFor(SOSAccount);
-
-
-bool SOSAccountEnsureFactoryCircles(SOSAccountRef a)
-{
-    bool result = false;
-    if (a)
-    {
-        require(a->factory, xit);
-        CFArrayRef circle_names = a->factory->copy_names(a->factory);
-        require(circle_names, xit);
-        CFArrayForEach(circle_names, ^(const void*name) {
-            if (isString(name))
-                SOSAccountEnsureCircle(a, (CFStringRef)name, NULL);
-        });
-
-        CFReleaseNull(circle_names);
-        result = true;
-    }
-xit:
-    return result;
-}
-
-
-SOSAccountRef SOSAccountCreateBasic(CFAllocatorRef allocator,
-                                           CFDictionaryRef gestalt,
-                                           SOSDataSourceFactoryRef factory) {
-    SOSAccountRef a = CFTypeAllocate(SOSAccount, struct __OpaqueSOSAccount, allocator);
-
-    a->queue = dispatch_queue_create("Account Queue", DISPATCH_QUEUE_SERIAL);
-
-    a->gestalt = CFRetainSafe(gestalt);
-
-    a->circles = CFDictionaryCreateMutableForCFTypes(allocator);
-    a->circle_identities = CFDictionaryCreateMutableForCFTypes(allocator);
-
-    a->factory = factory; // We adopt the factory. kthanksbai.
-
-    a->change_blocks = CFArrayCreateMutableForCFTypes(allocator);
-
-    a->departure_code = kSOSNeverAppliedToCircle;
-
-    a->key_transport = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(a, NULL);
-    a->circle_transports = CFDictionaryCreateMutableForCFTypes(allocator);
-    a->message_transports = CFDictionaryCreateMutableForCFTypes(allocator);
-
-    return a;
-}
-
-
-
-
-bool SOSAccountUpdateGestalt(SOSAccountRef account, CFDictionaryRef new_gestalt)
-{
-    if (CFEqual(new_gestalt, account->gestalt))
-        return false;
-    SOSAccountForEachKnownCircle(account, NULL, NULL, ^(SOSCircleRef circle, SOSFullPeerInfoRef full_peer) {
-        if (SOSFullPeerInfoUpdateGestalt(full_peer, new_gestalt, NULL)) {
-            SOSAccountModifyCircle(account, SOSCircleGetName(circle),
-                                   NULL, ^(SOSCircleRef circle_to_change) {
-                                       secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change");
-                                       return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(full_peer));
-                                   });
-        };
-    });
-
-    CFRetainAssign(account->gestalt, new_gestalt);
-    return true;
-}
-
-SOSAccountRef SOSAccountCreate(CFAllocatorRef allocator,
-                               CFDictionaryRef gestalt,
-                               SOSDataSourceFactoryRef factory) {
-    SOSAccountRef a = SOSAccountCreateBasic(allocator, gestalt, factory);
-
-    a->retired_peers = CFDictionaryCreateMutableForCFTypes(allocator);
-
-    SOSAccountEnsureFactoryCircles(a);
-
-    return a;
-}
-
-static void SOSAccountDestroy(CFTypeRef aObj) {
-    SOSAccountRef a = (SOSAccountRef) aObj;
-
-    // We don't own the factory, meerly have a reference to the singleton
-    //    don't free it.
-    //   a->factory
-    
-    CFReleaseNull(a->gestalt);
-    CFReleaseNull(a->circle_identities);
-    CFReleaseNull(a->circles);
-    CFReleaseNull(a->retired_peers);
-
-    a->user_public_trusted = false;
-    CFReleaseNull(a->user_public);
-    CFReleaseNull(a->user_key_parameters);
-
-    SOSAccountPurgePrivateCredential(a);
-    CFReleaseNull(a->previous_public);
-
-    a->departure_code = kSOSNeverAppliedToCircle;
-    CFReleaseNull(a->message_transports);
-    CFReleaseNull(a->key_transport);
-    CFReleaseNull(a->circle_transports);
-    dispatch_release(a->queue);
-}
-
-void SOSAccountSetToNew(SOSAccountRef a) {
-    secnotice("accountChange", "Setting Account to New");
-    CFAllocatorRef allocator = CFGetAllocator(a);
-    CFReleaseNull(a->circle_identities);
-    CFReleaseNull(a->circles);
-    CFReleaseNull(a->retired_peers);
-
-    CFReleaseNull(a->user_key_parameters);
-    CFReleaseNull(a->user_public);
-    CFReleaseNull(a->previous_public);
-    CFReleaseNull(a->_user_private);
-    
-    CFReleaseNull(a->key_transport);
-    CFReleaseNull(a->circle_transports);
-    CFReleaseNull(a->message_transports);
-    
-    a->user_public_trusted = false;
-    a->departure_code = kSOSNeverAppliedToCircle;
-    a->user_private_timer = 0;
-    a->lock_notification_token = 0;
-    
-    // keeping gestalt;
-    // keeping factory;
-    // Live Notification
-    // change_blocks;
-    // update_interest_block;
-    // update_block;
-    
-    a->circles = CFDictionaryCreateMutableForCFTypes(allocator);
-    a->circle_identities = CFDictionaryCreateMutableForCFTypes(allocator);
-    a->retired_peers = CFDictionaryCreateMutableForCFTypes(allocator);
-    
-    a->key_transport = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(a, NULL);
-    a->circle_transports = (CFMutableDictionaryRef)CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-    a->message_transports = (CFMutableDictionaryRef)CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-    
-    SOSAccountEnsureFactoryCircles(a);
-}
-
-
-static CFStringRef SOSAccountCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) {
-    SOSAccountRef a = (SOSAccountRef) aObj;
-    
-    return CFStringCreateWithFormat(NULL, NULL, CFSTR("<SOSAccount@%p: Gestalt: %@\n Circles: %@ CircleIDs: %@>"), a, a->gestalt, a->circles, a->circle_identities);
-}
-
-static Boolean SOSAccountCompare(CFTypeRef lhs, CFTypeRef rhs)
-{
-    SOSAccountRef laccount = (SOSAccountRef) lhs;
-    SOSAccountRef raccount = (SOSAccountRef) rhs;
-
-    return CFEqual(laccount->gestalt, raccount->gestalt)
-        && CFEqual(laccount->circles, raccount->circles)
-        && CFEqual(laccount->circle_identities, raccount->circle_identities);
-    //  ??? retired_peers
-}
-
-dispatch_queue_t SOSAccountGetQueue(SOSAccountRef account) {
-    return account->queue;
-}
-
-CFDictionaryRef SOSAccountGetMessageTransports(SOSAccountRef account){
-    return account->message_transports;
-}
-
-
-void SOSAccountSetUserPublicTrustedForTesting(SOSAccountRef account){
-    account->user_public_trusted = true;
-}
-
-CFArrayRef SOSAccountCopyAccountIdentityPeerInfos(SOSAccountRef account, CFAllocatorRef allocator, CFErrorRef* error)
-{
-    CFMutableArrayRef result = CFArrayCreateMutableForCFTypes(allocator);
-
-    CFDictionaryForEach(account->circle_identities, ^(const void *key, const void *value) {
-        SOSFullPeerInfoRef fpi = (SOSFullPeerInfoRef) value;
-        
-        CFArrayAppendValue(result, SOSFullPeerInfoGetPeerInfo(fpi));
-    });
-    
-    return result;
-}
-
-static bool SOSAccountThisDeviceCanSyncWithCircle(SOSAccountRef account, SOSCircleRef circle) {
-    CFErrorRef error = NULL;
-
-    if (!SOSAccountHasPublicKey(account, &error))
-        return false;
-
-    SOSFullPeerInfoRef myfpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), &error);
-    SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(myfpi);
-    CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi);
-    return SOSCircleHasPeerWithID(circle, myPeerID, &error);
-}
-
-static bool SOSAccountIsThisPeerIDMe(SOSAccountRef account, CFStringRef circleName, CFStringRef peerID) {
-    CFErrorRef error = NULL;
-    SOSFullPeerInfoRef myfpi = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, circleName, &error);
-    if (!myfpi) {
-        return false;
-    }
-    SOSPeerInfoRef mypi = SOSFullPeerInfoGetPeerInfo(myfpi);
-    CFStringRef myPeerID = SOSPeerInfoGetPeerID(mypi);
-    return CFEqualSafe(myPeerID, peerID);
-}
-
-bool SOSAccountSyncWithAllPeers(SOSAccountRef account, CFErrorRef *error)
-{
-    __block bool result = true;
-    
-    SOSAccountForEachCircle(account, ^(SOSCircleRef circle) {
-        
-        if (SOSAccountThisDeviceCanSyncWithCircle(account, circle)) {
-            CFStringRef circleName = SOSCircleGetName(circle);
-            SOSTransportMessageRef thisPeerTransport = (SOSTransportMessageRef)CFDictionaryGetValue(account->message_transports, SOSCircleGetName(circle));
-;
-            CFMutableDictionaryRef circleToPeerIDs = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-
-            SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
-                // Figure out transport for peer; for now we always use KVS
-                CFStringRef peerID = SOSPeerInfoGetPeerID(peer);
-                if (!SOSAccountIsThisPeerIDMe(account, circleName, peerID)) {
-                    CFArrayAppendValue(CFDictionaryEnsureCFArrayAndGetCurrentValue(circleToPeerIDs, circleName), peerID);
-                }
-            });
-            
-            result &= SOSTransportMessageSyncWithPeers(thisPeerTransport, circleToPeerIDs, error);
-            
-            CFReleaseNull(circleToPeerIDs);
-        }
-    });
-    
-    // Tell each transport to sync with its collection of peers we know we should sync with.
-
-
-    if (result)
-        SetCloudKeychainTraceValueForKey(kCloudKeychainNumberOfTimesSyncedWithPeers, 1);
-
-    
-    return result;
-}
-
-bool SOSAccountCleanupAfterPeer(SOSAccountRef account, size_t seconds, SOSCircleRef circle,
-                                SOSPeerInfoRef cleanupPeer, CFErrorRef* error)
-{
-    bool success = false;
-    if(!SOSAccountIsMyPeerActiveInCircle(account, circle, NULL)) return true;
-    
-    SOSPeerInfoRef myPeerInfo = SOSAccountGetMyPeerInCircle(account, circle, error);
-    require(myPeerInfo, xit);
-    
-    CFStringRef cleanupPeerID = SOSPeerInfoGetPeerID(cleanupPeer);
-    CFStringRef circle_name = SOSCircleGetName(circle);
-    
-    if (CFEqual(cleanupPeerID, SOSPeerInfoGetPeerID(myPeerInfo))) {
-        CFErrorRef destroyError = NULL;
-        if (!SOSAccountDestroyCirclePeerInfo(account, circle, &destroyError)) {
-            secerror("Unable to destroy peer info: %@", destroyError);
-        }
-        CFReleaseSafe(destroyError);
-        
-        account->departure_code = kSOSWithdrewMembership;
-        
-        return true;
-    }
-    
-    CFMutableDictionaryRef circleToPeerIDs = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-    CFArrayAppendValue(CFDictionaryEnsureCFArrayAndGetCurrentValue(circleToPeerIDs, circle_name), cleanupPeerID);
-
-    
-    CFErrorRef localError = NULL;
-    SOSTransportMessageRef tMessage = (SOSTransportMessageRef)CFDictionaryGetValue(account->message_transports, SOSCircleGetName(circle));
-    if (!SOSTransportMessageCleanupAfterPeerMessages(tMessage, circleToPeerIDs, &localError)) {
-        secnotice("account", "Failed to cleanup after peer %@ messages: %@", cleanupPeerID, localError);
-    }
-    CFReleaseNull(localError);
-    SOSTransportCircleRef tCircle = (SOSTransportCircleRef)CFDictionaryGetValue(account->circle_transports, SOSCircleGetName(circle));
-    if(SOSPeerInfoRetireRetirementTicket(seconds, cleanupPeer)) {
-        if (!SOSTransportCircleExpireRetirementRecords(tCircle, circleToPeerIDs, &localError)) {
-            secnotice("account", "Failed to cleanup after peer %@ retirement: %@", cleanupPeerID, localError);
-        }
-    }
-    CFReleaseNull(localError);
-    
-    CFReleaseNull(circleToPeerIDs);
-    
-xit:
-    return success;
-}
-
-bool SOSAccountCleanupRetirementTickets(SOSAccountRef account, size_t seconds, CFErrorRef* error) {
-    CFMutableDictionaryRef retirements_to_remove = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-    CFDictionaryRef original_retired_peers = account->retired_peers;
-    __block bool success = true;
-    account->retired_peers = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
-
-    CFDictionaryForEach(original_retired_peers, ^(const void *key, const void *value) {
-        if (isString(key) && isDictionary(value)) {
-            CFStringRef circle_name = key;
-            __block CFMutableDictionaryRef still_active_circle_retirements = NULL;
-            CFDictionaryForEach((CFMutableDictionaryRef) value, ^(const void *key, const void *value) {
-                if (isString(key) && isData(value)) {
-                    CFStringRef retired_peer_id = (CFStringRef) key;
-                    SOSPeerInfoRef retired_peer = SOSPeerInfoCreateFromData(kCFAllocatorDefault, NULL, (CFDataRef) value);
-                    if (retired_peer && SOSPeerInfoIsRetirementTicket(retired_peer) && CFEqual(retired_peer_id, SOSPeerInfoGetPeerID(retired_peer))) {
-                        // He's a retired peer all right, if he's active or not yet expired we keep a record of his retirement.
-                        // if not, clear any recordings of his retirement from our transport.
-                        if (SOSAccountIsActivePeerInCircleNamed(account, circle_name, retired_peer_id, NULL) ||
-                            !SOSPeerInfoRetireRetirementTicket(seconds, retired_peer)) {
-                            // He's still around or not expired. Keep record.
-                            if (still_active_circle_retirements == NULL) {
-                                still_active_circle_retirements = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(account->retired_peers, circle_name);
-                            }
-                            CFDictionarySetValue(still_active_circle_retirements, retired_peer_id, value);
-                        } else {
-                            CFMutableArrayRef retirements = CFDictionaryEnsureCFArrayAndGetCurrentValue(retirements_to_remove, circle_name);
-                            CFArrayAppendValue(retirements, retired_peer_id);
-                        }
-                    }
-                    CFReleaseNull(retired_peer);
-                }
-            });
-            
-            SOSTransportCircleRef tCircle = (SOSTransportCircleRef)CFDictionaryGetValue(account->circle_transports, circle_name);
-            success &= SOSTransportCircleExpireRetirementRecords(tCircle, retirements_to_remove, error);
-        }
-    });
-
-    CFReleaseNull(original_retired_peers);
-    CFReleaseNull(retirements_to_remove);
-
-    return success;
-}
-
-bool SOSAccountScanForRetired(SOSAccountRef account, SOSCircleRef circle, CFErrorRef *error) {
-    __block CFMutableDictionaryRef circle_retirees = (CFMutableDictionaryRef) CFDictionaryGetValue(account->retired_peers, SOSCircleGetName(circle));
-
-    SOSCircleForEachRetiredPeer(circle, ^(SOSPeerInfoRef peer) {
-        CFStringRef peer_id = SOSPeerInfoGetPeerID(peer);
-        if(!circle_retirees || !CFDictionaryGetValueIfPresent(circle_retirees, peer_id, NULL)) {
-            if (!circle_retirees) {
-                circle_retirees = CFDictionaryEnsureCFDictionaryAndGetCurrentValue(account->retired_peers, SOSCircleGetName(circle));
-            }
-            CFDataRef value = SOSPeerInfoCopyEncodedData(peer, NULL, NULL);
-            if(value) {
-                CFDictionarySetValue(circle_retirees, peer_id, value);
-                SOSAccountCleanupAfterPeer(account, RETIREMENT_FINALIZATION_SECONDS, circle, peer, error);
-            }
-            CFReleaseSafe(value);
-        }
-    });
-    return true;
-}
-
-SOSCircleRef SOSAccountCloneCircleWithRetirement(SOSAccountRef account, SOSCircleRef starting_circle, CFErrorRef *error) {
-    CFStringRef circle_to_mod = SOSCircleGetName(starting_circle);
-
-    SOSCircleRef new_circle = SOSCircleCopyCircle(NULL, starting_circle, error);
-    if(!new_circle) return NULL;
-
-    CFDictionaryRef circle_retirements = CFDictionaryGetValue(account->retired_peers, circle_to_mod);
-
-    if (isDictionary(circle_retirements)) {
-        CFDictionaryForEach(circle_retirements, ^(const void* id, const void* value) {
-            if (isData(value)) {
-                SOSPeerInfoRef pi = SOSPeerInfoCreateFromData(NULL, error, (CFDataRef) value);
-                if (pi && CFEqualSafe(id, SOSPeerInfoGetPeerID(pi))) {
-                    SOSCircleUpdatePeerInfo(new_circle, pi);
-                }
-                CFReleaseSafe(pi);
-            }
-        });
-    }
-    
-    if(SOSCircleCountPeers(new_circle) == 0) {
-        SOSCircleResetToEmpty(new_circle, NULL);
-    }
-    
-    return new_circle;
-}
-
-//
-// MARK: Circle Membership change notificaion
-//
-
-void SOSAccountAddChangeBlock(SOSAccountRef a, SOSAccountCircleMembershipChangeBlock changeBlock) {
-    CFArrayAppendValue(a->change_blocks, changeBlock);
-}
-
-void SOSAccountRemoveChangeBlock(SOSAccountRef a, SOSAccountCircleMembershipChangeBlock changeBlock) {
-    CFArrayRemoveAllValue(a->change_blocks, changeBlock);
-}
-
-void SOSAccountAddSyncablePeerBlock(SOSAccountRef a, CFStringRef ds_name, SOSAccountSyncablePeersBlock changeBlock) {
-    if (!changeBlock) return;
-
-    CFRetainSafe(ds_name);
-    SOSAccountCircleMembershipChangeBlock block_to_register = ^void (SOSCircleRef new_circle,
-                                                                     CFSetRef added_peers, CFSetRef removed_peers,
-                                                                     CFSetRef added_applicants, CFSetRef removed_applicants) {
-
-        if (!CFEqualSafe(SOSCircleGetName(new_circle), ds_name))
-            return;
-
-        SOSPeerInfoRef myPi = SOSAccountGetMyPeerInCircle(a, new_circle, NULL);
-        CFStringRef myPi_id = myPi ? SOSPeerInfoGetPeerID(myPi) : NULL;
-
-        CFMutableArrayRef peer_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-        CFMutableArrayRef added_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-        CFMutableArrayRef removed_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-
-        if (SOSCircleHasPeer(new_circle, myPi, NULL)) {
-            SOSCircleForEachPeer(new_circle, ^(SOSPeerInfoRef peer) {
-                CFArrayAppendValueIfNot(peer_ids, SOSPeerInfoGetPeerID(peer), myPi_id);
-            });
-
-            CFSetForEach(added_peers, ^(const void *value) {
-                CFArrayAppendValueIfNot(added_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id);
-            });
-
-            CFSetForEach(removed_peers, ^(const void *value) {
-                CFArrayAppendValueIfNot(removed_ids, SOSPeerInfoGetPeerID((SOSPeerInfoRef) value), myPi_id);
-            });
-        }
-
-        if (CFArrayGetCount(peer_ids) || CFSetContainsValue(removed_peers, myPi))
-            changeBlock(peer_ids, added_ids, removed_ids);
-
-        CFReleaseSafe(peer_ids);
-        CFReleaseSafe(added_ids);
-        CFReleaseSafe(removed_ids);
-    };
-
-    CFRetainSafe(changeBlock);
-    SOSAccountAddChangeBlock(a, Block_copy(block_to_register));
-
-    CFSetRef empty = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
-    SOSCircleRef circle = (SOSCircleRef) CFDictionaryGetValue(a->circles, ds_name);
-    if (circle) {
-        block_to_register(circle, empty, empty, empty, empty);
-    }
-    CFReleaseSafe(empty);
-}
-
-
-bool sosAccountLeaveCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error) {
-    SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircle(account, circle, NULL);
-    if(!fpi) return false;
-    if(!SOSFullPeerInfoValidate(fpi, NULL)) return false;
-       CFErrorRef localError = NULL;
-       SOSPeerInfoRef retire_peer = SOSFullPeerInfoPromoteToRetiredAndCopy(fpi, &localError);
-    CFStringRef retire_id = SOSPeerInfoGetPeerID(retire_peer);
-    
-    // Account should move away from a dictionary of KVS keys to a Circle -> Peer -> Retirement ticket storage soonish.
-       CFStringRef retire_key = SOSRetirementKeyCreateWithCircleAndPeer(circle, retire_id);
-       CFDataRef retire_value = NULL;
-    bool retval = false;
-    bool writeCircle = false;
-    
-    // Create a Retirement Ticket and store it in the retired_peers of the account.
-    require_action_quiet(retire_peer, errout, secerror("Create ticket failed for peer %@: %@", fpi, localError));
-       retire_value = SOSPeerInfoCopyEncodedData(retire_peer, NULL, &localError);
-    require_action_quiet(retire_value, errout, secerror("Failed to encode retirement peer %@: %@", retire_peer, localError));
-
-    // See if we need to repost the circle we could either be an applicant or a peer already in the circle
-    if(SOSCircleHasApplicant(circle, retire_peer, NULL)) {
-           // Remove our application if we have one.
-           SOSCircleWithdrawRequest(circle, retire_peer, NULL);
-        writeCircle = true;
-    } else if (SOSCircleHasPeer(circle, retire_peer, NULL)) {
-        if (SOSCircleUpdatePeerInfo(circle, retire_peer)) {
-            CFErrorRef cleanupError = NULL;
-            if (!SOSAccountCleanupAfterPeer(account, RETIREMENT_FINALIZATION_SECONDS, circle, retire_peer, &cleanupError))
-                secerror("Error cleanup up after peer (%@): %@", retire_peer, cleanupError);
-            CFReleaseSafe(cleanupError);
-        }
-        writeCircle = true;
-    }
-    
-    // Store the retirement record locally.
-    CFDictionarySetValue(account->retired_peers, retire_key, retire_value);
-
-    // Write retirement to Transport
-    SOSTransportCircleRef tCircle = (SOSTransportCircleRef)CFDictionaryGetValue(account->circle_transports, SOSCircleGetName(circle));
-    SOSTransportCirclePostRetirement(tCircle, SOSCircleGetName(circle), retire_id, retire_value, NULL); // TODO: Handle errors?
-    
-    // Kill peer key but don't return error if we can't.
-    if(!SOSAccountDestroyCirclePeerInfo(account, circle, &localError))
-        secerror("Couldn't purge key for peer %@ on retirement: %@", fpi, localError);
-
-    if (writeCircle) {
-        CFDataRef circle_data = SOSCircleCopyEncodedData(circle, kCFAllocatorDefault, error);
-        
-        if (circle_data) {
-            SOSTransportCirclePostCircle(tCircle, SOSCircleGetName(circle), circle_data, NULL); // TODO: Handle errors?
-        }
-        CFReleaseNull(circle_data);
-    }
-    retval = true;
-
-errout:
-    CFReleaseNull(localError);
-    CFReleaseNull(retire_peer);
-    CFReleaseNull(retire_key);
-    CFReleaseNull(retire_value);
-    return retval;
-}
-
-/*
-    NSUbiquitousKeyValueStoreInitialSyncChange is only posted if there is any
-    local value that has been overwritten by a distant value. If there is no
-    conflict between the local and the distant values when doing the initial
-    sync (e.g. if the cloud has no data stored or the client has not stored
-    any data yet), you'll never see that notification.
-
-    NSUbiquitousKeyValueStoreInitialSyncChange implies an initial round trip
-    with server but initial round trip with server does not imply
-    NSUbiquitousKeyValueStoreInitialSyncChange.
- */
-
-
-//
-// MARK: Status summary
-//
-
-static SOSCCStatus SOSCCCircleStatus(SOSCircleRef circle) {
-    if (SOSCircleCountPeers(circle) == 0)
-        return kSOSCCCircleAbsent;
-
-    return kSOSCCNotInCircle;
-}
-
-static SOSCCStatus SOSCCThisDeviceStatusInCircle(SOSCircleRef circle, SOSPeerInfoRef this_peer) {
-    if (SOSCircleCountPeers(circle) == 0)
-        return kSOSCCCircleAbsent;
-
-    if (SOSCircleHasPeer(circle, this_peer, NULL))
-        return kSOSCCInCircle;
-
-    if (SOSCircleHasApplicant(circle, this_peer, NULL))
-        return kSOSCCRequestPending;
-
-    return kSOSCCNotInCircle;
-}
-
-static SOSCCStatus UnionStatus(SOSCCStatus accumulated_status, SOSCCStatus additional_circle_status) {
-    switch (additional_circle_status) {
-        case kSOSCCInCircle:
-            return accumulated_status;
-        case kSOSCCRequestPending:
-            return (accumulated_status == kSOSCCInCircle) ?
-            kSOSCCRequestPending :
-            accumulated_status;
-        case kSOSCCNotInCircle:
-            return (accumulated_status == kSOSCCInCircle ||
-                    accumulated_status == kSOSCCRequestPending) ?
-            kSOSCCNotInCircle :
-            accumulated_status;
-        case kSOSCCCircleAbsent:
-            return (accumulated_status == kSOSCCInCircle ||
-                    accumulated_status == kSOSCCRequestPending ||
-                    accumulated_status == kSOSCCNotInCircle) ?
-            kSOSCCCircleAbsent :
-            accumulated_status;
-        default:
-            return additional_circle_status;
-    };
-
-}
-
-SOSCCStatus SOSAccountIsInCircles(SOSAccountRef account, CFErrorRef* error) {
-    if (!SOSAccountHasPublicKey(account, error)) {
-        return kSOSCCError;
-    }
-
-    __block bool set_once = false;
-    __block SOSCCStatus status = kSOSCCInCircle;
-
-    SOSAccountForEachKnownCircle(account, ^(CFStringRef name) {
-        set_once = true;
-        status = UnionStatus(status, kSOSCCNotInCircle);
-    }, ^(SOSCircleRef circle) {
-        set_once = true;
-        status = UnionStatus(status, SOSCCCircleStatus(circle));
-    }, ^(SOSCircleRef circle, SOSFullPeerInfoRef full_peer) {
-        set_once = true;
-        SOSCCStatus circle_status = SOSCCThisDeviceStatusInCircle(circle, SOSFullPeerInfoGetPeerInfo(full_peer));
-        status = UnionStatus(status, circle_status);
-    });
-
-    if (!set_once)
-        status = kSOSCCCircleAbsent;
-
-    return status;
-}
-
-//
-// MARK: Account Reset Circles
-//
-
-static bool SOSAccountResetThisCircleToOffering(SOSAccountRef account, SOSCircleRef circle, SecKeyRef user_key, CFErrorRef *error) {
-    SOSFullPeerInfoRef myCirclePeer = SOSAccountMakeMyFullPeerInCircleNamed(account, SOSCircleGetName(circle), error);
-    if (!myCirclePeer)
-        return false;
-    if(!SOSFullPeerInfoValidate(myCirclePeer, NULL)) return false;
-
-    
-    SOSAccountModifyCircle(account, SOSCircleGetName(circle), error, ^(SOSCircleRef circle) {
-        bool result = false;
-        SOSFullPeerInfoRef cloud_identity = NULL;
-        CFErrorRef localError = NULL;
-
-        require_quiet(SOSCircleResetToOffering(circle, user_key, myCirclePeer, &localError), err_out);
-
-        {
-            SOSPeerInfoRef cloud_peer = GenerateNewCloudIdentityPeerInfo(error);
-            require_quiet(cloud_peer, err_out);
-            cloud_identity = CopyCloudKeychainIdentity(cloud_peer, error);
-            CFReleaseNull(cloud_peer);
-            require_quiet(cloud_identity, err_out);
-        }
-
-        account->departure_code = kSOSNeverLeftCircle;
-        require_quiet(SOSCircleRequestAdmission(circle, user_key, cloud_identity, &localError), err_out);
-        require_quiet(SOSCircleAcceptRequest(circle, user_key, myCirclePeer, SOSFullPeerInfoGetPeerInfo(cloud_identity), &localError), err_out);
-        result = true;
-        SOSAccountPublishCloudParameters(account, NULL);
-
-    err_out:
-        if (result == false)
-            secerror("error resetting circle (%@) to offering: %@", circle, localError);
-        if (localError && error && *error == NULL) {
-            *error = localError;
-            localError = NULL;
-        }
-        CFReleaseNull(localError);
-        CFReleaseNull(cloud_identity);
-        return result;
-    });
-
-    return true;
-}
-
-
-bool SOSAccountResetToOffering(SOSAccountRef account, CFErrorRef* error) {
-    SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error);
-    if (!user_key)
-        return false;
-    
-    __block bool result = true;
-    
-    SOSAccountForEachKnownCircle(account, ^(CFStringRef name) {
-        SOSCircleRef circle = SOSCircleCreate(NULL, name, NULL);
-        if (circle)
-            CFDictionaryAddValue(account->circles, name, circle);
-        
-        SOSAccountResetThisCircleToOffering(account, circle, user_key, error);
-    }, ^(SOSCircleRef circle) {
-        SOSAccountResetThisCircleToOffering(account, circle, user_key, error);
-    }, ^(SOSCircleRef circle, SOSFullPeerInfoRef full_peer) {
-        SOSAccountResetThisCircleToOffering(account, circle, user_key, error);
-    });
-    
-    return result;
-}
-
-bool SOSAccountResetToEmpty(SOSAccountRef account, CFErrorRef* error) {
-    if (!SOSAccountHasPublicKey(account, error))
-        return false;
-    
-    __block bool result = true;
-    SOSAccountForEachCircle(account, ^(SOSCircleRef circle) {
-        SOSAccountModifyCircle(account, SOSCircleGetName(circle), error, ^(SOSCircleRef circle) {
-            if (!SOSCircleResetToEmpty(circle, error))
-            {
-                secerror("error: %@", *error);
-                result = false;
-            }
-            account->departure_code = kSOSWithdrewMembership;
-            return result;
-        });
-    });
-    
-    return result;
-}
-
-
-//
-// MARK: Joining
-//
-
-static bool SOSAccountJoinThisCircle(SOSAccountRef account, SecKeyRef user_key,
-                                     SOSCircleRef circle, bool use_cloud_peer, CFErrorRef* error) {
-    __block bool result = false;
-    __block SOSFullPeerInfoRef cloud_full_peer = NULL;
-
-    SOSFullPeerInfoRef myCirclePeer = SOSAccountMakeMyFullPeerInCircleNamed(account, SOSCircleGetName(circle), error);
-    
-    require_action_quiet(myCirclePeer, fail,
-                         SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Can't find/create peer for circle: %@"), circle));
-    if (use_cloud_peer) {
-        cloud_full_peer = SOSCircleGetiCloudFullPeerInfoRef(circle);
-    }
-    
-    if (SOSCircleCountPeers(circle) == 0) {
-        result = SOSAccountResetThisCircleToOffering(account, circle, user_key, error);
-    } else {
-        SOSAccountModifyCircle(account, SOSCircleGetName(circle), error, ^(SOSCircleRef circle) {
-            result = SOSCircleRequestAdmission(circle, user_key, myCirclePeer, error);
-            account->departure_code = kSOSNeverLeftCircle;
-            if(result && cloud_full_peer) {
-                CFErrorRef localError = NULL;
-                CFStringRef cloudid = SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(cloud_full_peer));
-                require_quiet(cloudid, finish);
-                require_quiet(SOSCircleHasActivePeerWithID(circle, cloudid, &localError), finish);
-                require_quiet(SOSCircleAcceptRequest(circle, user_key, cloud_full_peer, SOSFullPeerInfoGetPeerInfo(myCirclePeer), &localError), finish);
-            finish:
-                if (localError){
-                    secerror("Failed to join with cloud identity: %@", localError);
-                    CFReleaseNull(localError);
-                }
-            }
-            return result;
-        });
-    }
-    
-fail:
-    CFReleaseNull(cloud_full_peer);
-    return result;
-}
-                           
-static bool SOSAccountJoinCircles_internal(SOSAccountRef account, bool use_cloud_identity, CFErrorRef* error) {
-    SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error);
-    if (!user_key)
-        return false;
-
-    __block bool success = true;
-    
-    SOSAccountForEachKnownCircle(account, ^(CFStringRef name) { // Incompatible
-        success = false;
-        SOSCreateError(kSOSErrorIncompatibleCircle, CFSTR("Incompatible circle"), NULL, error);
-    }, ^(SOSCircleRef circle) { //no peer
-        success = SOSAccountJoinThisCircle(account, user_key, circle, use_cloud_identity, error) && success;
-    }, ^(SOSCircleRef circle, SOSFullPeerInfoRef full_peer) {   // Have Peer
-        SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(full_peer);
-        if(SOSCircleHasPeer(circle, myPeer, NULL)) goto already_present;
-        if(SOSCircleHasApplicant(circle, myPeer, NULL))  goto already_applied;
-        if(SOSCircleHasRejectedApplicant(circle, myPeer, NULL)) {
-            SOSCircleRemoveRejectedPeer(circle, myPeer, NULL);
-        }
-        
-        secerror("Resetting my peer (ID: %@) for circle '%@' during application", SOSPeerInfoGetPeerID(myPeer), SOSCircleGetName(circle));
-        CFErrorRef localError = NULL;
-        if (!SOSAccountDestroyCirclePeerInfo(account, circle, &localError)) {
-            secerror("Failed to destroy peer (%@) during application, error=%@", myPeer, localError);
-            CFReleaseNull(localError);
-        }
-    already_applied:
-        success = SOSAccountJoinThisCircle(account, user_key, circle, use_cloud_identity, error) && success;
-        return;
-    already_present:
-        success = true;
-        return;
-    });
-
-    if(success) account->departure_code = kSOSNeverLeftCircle;
-    return success;
-}
-
-bool SOSAccountJoinCircles(SOSAccountRef account, CFErrorRef* error) {
-    return SOSAccountJoinCircles_internal(account, false, error);
-}
-
-CFStringRef SOSAccountGetDeviceID(SOSAccountRef account, CFErrorRef *error){
-    __block CFStringRef result = NULL;
-    __block CFStringRef temp = NULL;
-    SOSAccountForEachKnownCircle(account, NULL, NULL, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer) {
-            SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircle(account, circle, error);
-            if(fpi){
-                SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
-                if(myPeer){
-                    temp = SOSPeerInfoGetDeviceID(myPeer);
-                    if(!isNull(temp)){
-                        result = CFStringCreateCopy(kCFAllocatorDefault, temp);
-                    }
-                }
-                else{
-                    secnotice("circle", "Could not acquire my peer info in circle: %@", SOSCircleGetName(circle));
-                }
-            }
-            else{
-                secnotice("circle", "Could not acquire my full peer info in circle: %@", SOSCircleGetName(circle));
-            }
-    });
-    return result;
-}
-
-bool SOSAccountSetMyDSID(SOSAccountRef account, CFStringRef IDS, CFErrorRef* error){
-    __block bool result = false;
-    
-    SOSAccountForEachKnownCircle(account, NULL, NULL, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer) {
-        SOSAccountModifyCircle(account, SOSCircleGetName(circle), error, ^(SOSCircleRef circle) {
-            SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircle(account, circle, error);
-            if(fpi){
-                SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
-                if(myPeer){
-                    SOSPeerInfoSetDeviceID(myPeer, IDS);
-                    result = true;
-                }
-                else{
-                    secnotice("circle", "Could not acquire my peer info in circle: %@", SOSCircleGetName(circle));
-                    result = false;
-                }
-            }
-            else{
-                secnotice("circle", "Could not acquire my full peer info in circle: %@", SOSCircleGetName(circle));
-                result = false;
-            }
-            return result;
-        });
-    });
-    return result;
-    
-}
-bool SOSAccountJoinCirclesAfterRestore(SOSAccountRef account, CFErrorRef* error) {
-    return SOSAccountJoinCircles_internal(account, true, error);
-}
-
-
-bool SOSAccountLeaveCircles(SOSAccountRef account, CFErrorRef* error)
-{
-    __block bool result = true;
-    SOSAccountForEachKnownCircle(account, NULL, NULL, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer) {
-        SOSAccountModifyCircle(account, SOSCircleGetName(circle), error, ^(SOSCircleRef circle) {
-            result = sosAccountLeaveCircle(account, circle, error); // TODO: What about multiple errors!
-            return result;
-               });
-    });
-
-    account->departure_code = kSOSWithdrewMembership;
-    return result;
-}
-
-bool SOSAccountBail(SOSAccountRef account, uint64_t limit_in_seconds, CFErrorRef* error) {
-    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-    dispatch_group_t group = dispatch_group_create();
-    __block bool result = false;
-    secnotice("circle", "Attempting to leave circle - best effort - in %llu seconds\n", limit_in_seconds);
-    // Add a task to the group
-    dispatch_group_async(group, queue, ^{
-        SOSAccountForEachKnownCircle(account, NULL, NULL, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer) {
-            SOSAccountModifyCircle(account, SOSCircleGetName(circle), error, ^(SOSCircleRef circle) {
-                result = sosAccountLeaveCircle(account, circle, error); // TODO: What about multiple errors!
-                return result;
-            });
-        });
-        
-        account->departure_code = kSOSWithdrewMembership;
-    });
-    dispatch_time_t milestone = dispatch_time(DISPATCH_TIME_NOW, limit_in_seconds * NSEC_PER_SEC);
-
-    dispatch_group_wait(group, milestone);
-    dispatch_release(group);
-    return result;
-}
-
-
-//
-// MARK: Application
-//
-
-static void for_each_applicant_in_each_circle(SOSAccountRef account, CFArrayRef peer_infos,
-                                              bool (^action)(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer)) {
-
-    SOSAccountForEachKnownCircle(account, NULL, NULL, ^(SOSCircleRef circle, SOSFullPeerInfoRef full_peer) {
-        SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(full_peer);
-        CFErrorRef peer_error = NULL;
-        if (SOSCircleHasPeer(circle, me, &peer_error)) {
-            CFArrayForEach(peer_infos, ^(const void *value) {
-                SOSPeerInfoRef peer = (SOSPeerInfoRef) value;
-                if (SOSCircleHasApplicant(circle, peer, NULL)) {
-                    SOSAccountModifyCircle(account, SOSCircleGetName(circle), NULL, ^(SOSCircleRef circle) {
-                        return action(circle, full_peer, peer);
-                    });
-                }
-            });
-        }
-        if (peer_error)
-            secerror("Got error in SOSCircleHasPeer: %@", peer_error);
-        CFReleaseSafe(peer_error); // TODO: We should be accumulating errors here.
-    });
-}
-
-bool SOSAccountAcceptApplicants(SOSAccountRef account, CFArrayRef applicants, CFErrorRef* error) {
-    SecKeyRef user_key = SOSAccountGetPrivateCredential(account, error);
-    if (!user_key)
-        return false;
-
-    __block bool success = true;
-       __block int64_t num_peers = 0;
-
-    for_each_applicant_in_each_circle(account, applicants, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer) {
-        bool accepted = SOSCircleAcceptRequest(circle, user_key, myCirclePeer, peer, error);
-        if (!accepted)
-            success = false;
-               else
-                       num_peers = MAX(num_peers, SOSCircleCountPeers(circle));
-        return accepted;
-    });
-       
-    return success;
-}
-
-bool SOSAccountRejectApplicants(SOSAccountRef account, CFArrayRef applicants, CFErrorRef* error) {
-    __block bool success = true;
-       __block int64_t num_peers = 0;
-
-    for_each_applicant_in_each_circle(account, applicants, ^(SOSCircleRef circle, SOSFullPeerInfoRef myCirclePeer, SOSPeerInfoRef peer) {
-        bool rejected = SOSCircleRejectRequest(circle, myCirclePeer, peer, error);
-        if (!rejected)
-            success = false;
-               else
-                       num_peers = MAX(num_peers, SOSCircleCountPeers(circle));
-        return rejected;
-    });
-
-    return success;
-}
-
-
-
-CFStringRef SOSAccountCopyIncompatibilityInfo(SOSAccountRef account, CFErrorRef* error) {
-    return CFSTR("We're compatible, go away");
-}
-
-enum DepartureReason SOSAccountGetLastDepartureReason(SOSAccountRef account, CFErrorRef* error) {
-    return account->departure_code;
-}
-
-
-CFArrayRef SOSAccountCopyGeneration(SOSAccountRef account, CFErrorRef *error) {
-    if (!SOSAccountHasPublicKey(account, error))
-        return NULL;
-    CFMutableArrayRef generations = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-    
-    SOSAccountForEachCircle(account, ^(SOSCircleRef circle) {
-        CFNumberRef generation = (CFNumberRef)SOSCircleGetGeneration(circle);
-        CFArrayAppendValue(generations, SOSCircleGetName(circle));
-        CFArrayAppendValue(generations, generation);
-    });
-    
-    return generations;
-    
-}
-
-bool SOSValidateUserPublic(SOSAccountRef account, CFErrorRef *error) {
-    if (!SOSAccountHasPublicKey(account, error))
-        return NULL;
-
-    return account->user_public_trusted;
-}
-
-
-bool SOSAccountEnsurePeerRegistration(SOSAccountRef account, CFErrorRef *error) {
-    __block bool result = true;
-    
-    secnotice("updates", "Ensuring peer registration.");
-    
-    SOSAccountForEachKnownCircle(account, ^(CFStringRef name) {
-    }, ^(SOSCircleRef circle) {
-    }, ^(SOSCircleRef circle, SOSFullPeerInfoRef full_peer) {
-        SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircle(account, circle, error);
-        SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(fpi);
-        CFMutableArrayRef trusted_peer_ids = NULL;
-        CFMutableArrayRef untrusted_peer_ids = NULL;
-        CFStringRef my_id = NULL;
-        if (SOSCircleHasPeer(circle, me, NULL)) {
-            my_id = SOSPeerInfoGetPeerID(me);
-            trusted_peer_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-            untrusted_peer_ids = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
-            SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
-                CFMutableArrayRef arrayToAddTo = SOSPeerInfoApplicationVerify(peer, account->user_public, NULL) ? trusted_peer_ids : untrusted_peer_ids;
-
-                CFArrayAppendValueIfNot(arrayToAddTo, SOSPeerInfoGetPeerID(peer), my_id);
-            });
-        }
-
-        SOSEngineRef engine = SOSDataSourceFactoryGetEngineForDataSourceName(account->factory, SOSCircleGetName(circle), NULL);
-        if (engine)
-            SOSEngineCircleChanged(engine, my_id, trusted_peer_ids, untrusted_peer_ids);
-
-        CFReleaseNull(trusted_peer_ids);
-        CFReleaseNull(untrusted_peer_ids);
-
-        SOSTransportMessageRef transport = (SOSTransportMessageRef)CFDictionaryGetValue(account->message_transports, SOSCircleGetName(circle));
-        SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef peer) {
-            if (!CFEqualSafe(me, peer)) {
-                CFErrorRef localError = NULL;
-                SOSPeerCoderInitializeForPeer(transport, full_peer, peer, &localError);
-                if (localError)
-                    secnotice("updates", "can't initialize transport for peer %@ with %@ (%@)", peer, full_peer, localError);
-                CFReleaseSafe(localError);
-            }
-        });
-    });
-    
-    return result;
-}