bool SOSKeychainAccountSetFactoryForAccount(SOSCCAccountDataSourceFactoryBlock block)
{
accountDataSourceOverride = Block_copy(block);
-
+
return true;
}
{
if (NULL == der)
return NULL;
-
+
size_t payload_size = 0;
const uint8_t *payload = ccder_decode_tl(CCDER_BOOLEAN, &payload_size, der, der_end);
-
+
if (NULL == payload || (der_end - payload) < 1 || payload_size != 1) {
return NULL;
}
-
+
if (boolean)
*boolean = (*payload != 0);
-
+
return payload + payload_size;
}
CFDataRef accountStatus = (CFDataRef) CFPropertyListReadFromFile(accountStatusFileURL);
CFReleaseSafe(accountStatusFileURL);
bool circle_on = false;
-
+
if (accountStatus && !isData(accountStatus)) {
CFReleaseNull(accountStatus);
} else if(accountStatus) {
size_t size = CFDataGetLength(accountStatus);
const uint8_t *der = CFDataGetBytePtr(accountStatus);
const uint8_t *der_p = der;
-
+
const uint8_t *sequence_end;
der_p = ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, &sequence_end, der_p, der_p + size);
der_p = ccder_decode_bool(&circle_on, der_p, sequence_end);
} else {
-
+
}
return circle_on;
}
static uint8_t* ccder_encode_bool(bool value, const uint8_t *der, uint8_t *der_end)
{
uint8_t value_byte = value;
-
+
return ccder_encode_tl(CCDER_BOOLEAN, 1, der,
ccder_encode_body(1, &value_byte, der, der_end));
}
ccder_encode_bool(account_on, der, der_end));
CFDataRef accountStatusAsData = CFDataCreate(kCFAllocatorDefault, der_end, der_size);
-
+
require_quiet(accountStatusAsData, exit);
if (sLastSavedAccountStatus && CFEqual(sLastSavedAccountStatus, accountStatusAsData)) goto exit;
-
+
CFURLRef accountStatusFileURL = SecCopyURLForFileInKeychainDirectory(accountStatusFileName);
CFPropertyListWriteToFile((CFPropertyListRef) accountStatusAsData, accountStatusFileURL);
CFReleaseSafe(accountStatusFileURL);
-
+
CFReleaseNull(sLastSavedAccountStatus);
sLastSavedAccountStatus = accountStatusAsData;
accountStatusAsData = NULL;
-
+
exit:
CFReleaseNull(saveError);
CFReleaseNull(accountStatusAsData);
}
+static void SOSCCCircleIsOn_UpdateArtifact(SOSCCStatus status)
+{
+ switch (status) {
+ case kSOSCCCircleAbsent:
+ case kSOSCCNotInCircle:
+ SOSCCCircleIsOn_SetArtifact(false);
+ break;
+ case kSOSCCInCircle:
+ case kSOSCCRequestPending:
+ SOSCCCircleIsOn_SetArtifact(true);
+ break;
+ case kSOSCCError:
+ default:
+ // do nothing
+ break;
+ }
+}
static void SOSKeychainAccountEnsureSaved(SOSAccountRef account)
{
static CFDataRef sLastSavedAccountData = NULL;
-
+
CFErrorRef saveError = NULL;
- SOSCCStatus currentStatus = SOSAccountIsInCircles(account, NULL);
- bool account_on = (currentStatus == kSOSCCCircleAbsent || currentStatus == kSOSCCNotInCircle) ? false: true;
- SOSCCCircleIsOn_SetArtifact(account_on);
-
+ SOSCCCircleIsOn_UpdateArtifact(SOSAccountIsInCircles(account, NULL));
+
CFDataRef accountAsData = SOSAccountCopyEncodedData(account, kCFAllocatorDefault, &saveError);
-
+
require_action_quiet(accountAsData, exit, secerror("Failed to transform account into data, error: %@", saveError));
require_quiet(!CFEqualSafe(sLastSavedAccountData, accountAsData), exit);
-
+
if (!SOSItemUpdateOrAdd(kSOSAccountLabel, kSecAttrAccessibleAlwaysThisDeviceOnly, accountAsData, &saveError)) {
secerror("Can't save account: %@", saveError);
goto exit;
}
-
+
CFReleaseNull(sLastSavedAccountData);
sLastSavedAccountData = accountAsData;
accountAsData = NULL;
-
+
exit:
CFReleaseNull(saveError);
CFReleaseNull(accountAsData);
CFReleaseNull(error);
};
-
+
SOSAccountDataUpdateBlock updateKVS = ^ bool (CFDictionaryRef changes, CFErrorRef *error) {
SOSCloudKeychainPutObjectsInCloud(changes, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), log_error);
};
secdebug("account", "Created account");
-
+
CFDataRef savedAccount = SOSKeychainCopySavedAccountData();
-
+
// At this point we might have an account structure from keychain that may or may not match the account we're building this for
// murf ZZZ we should probably make sure this is a good thing before using it.
SOSAccountRef account = NULL;
-
+
if (savedAccount) {
CFErrorRef inflationError = NULL;
SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride() : SecItemDataSourceFactoryCreateDefault();
account = SOSAccountCreateFromData(kCFAllocatorDefault, savedAccount, factory, updateKVSKeys, updateKVS, &inflationError);
-
+
if (account)
SOSAccountUpdateGestalt(account, our_gestalt);
else
}
CFReleaseSafe(savedAccount);
-
+
if (!account) {
// If we get here then we are creating a new accout and so increment the peer count for ourselves.
SOSDataSourceFactoryRef factory = accountDataSourceOverride ? accountDataSourceOverride() : SecItemDataSourceFactoryCreateDefault();
static void do_with_account_dynamic(void (^action)(SOSAccountRef account), bool sync) {
static SOSAccountRef sSharedAccount;
static dispatch_once_t onceToken;
-
+
dispatch_once(&onceToken, ^{
secdebug(SOSCKCSCOPE, "Account Creation start");
-
+
CFDictionaryRef gestalt = RegisterForGestaltUpdate(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), NULL);
-
+
if (!gestalt) {
#if TARGET_OS_IPHONE && TARGET_IPHONE_SIMULATOR
gestalt = CFDictionaryCreateForCFTypes(kCFAllocatorDefault, NULL);
sSharedAccount = SOSKeychainAccountCreateSharedAccount(gestalt);
CFReleaseSafe(gestalt);
-
+
SOSCCSetThisDeviceDefinitelyNotActiveInCircle(SOSAccountIsInCircles(sSharedAccount, NULL));
-
+
SOSAccountAddChangeBlock(sSharedAccount, ^(SOSCircleRef circle,
CFArrayRef peer_additions, CFArrayRef peer_removals,
CFArrayRef applicant_additions, CFArrayRef applicant_removals) {
CFReleaseNull(pi_error);
} else {
CFReleaseSafe(pi_error);
-
+
if (CFArrayContainsValue(peer_additions, CFRangeMake(0, CFArrayGetCount(peer_additions)), me)) {
SOSCCSyncWithAllPeers();
}
CFArrayGetCount(peer_removals) != 0 ||
CFArrayGetCount(applicant_additions) != 0 ||
CFArrayGetCount(applicant_removals) != 0) {
-
+
SOSCCSetThisDeviceDefinitelyNotActiveInCircle(SOSAccountIsInCircles(sSharedAccount, NULL));
notify_post(kSOSCCCircleChangedNotification);
}
});
-
+
SOSCloudKeychainSetItemsChangedBlock(^(CFDictionaryRef changes) {
CFRetainSafe(changes);
do_with_account_async(^(SOSAccountRef account) {
CFStringRef changeDescription = SOSChangesCopyDescription(changes, false);
secdebug(SOSCKCSCOPE, "Received: %@", changeDescription);
CFReleaseSafe(changeDescription);
-
+
CFErrorRef error = NULL;
if (!SOSAccountHandleUpdates(account, changes, &error)) {
secerror("Error handling updates: %@", error);
});
});
-
+
dispatch_block_t do_action_and_save = ^{
action(sSharedAccount);
SOSKeychainAccountEnsureSaved(sSharedAccount);
SOSAccountRef SOSKeychainAccountGetSharedAccount()
{
__block SOSAccountRef result = NULL;
-
+
do_with_account(^(SOSAccountRef account) {
result = account;
});
-
+
return result;
}
static bool EnsureFreshParameters(SOSAccountRef account, CFErrorRef *error) {
dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
dispatch_retain(wait_for); // Both this scope and the block own it.
-
+
CFMutableArrayRef keysToGet = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
CFArrayAppendValue(keysToGet, kSOSKVSKeyParametersKey);
-
+
__block CFDictionaryRef valuesToUpdate = NULL;
__block bool success = false;
-
+
SOSAccountForEachCircle(account, ^(SOSCircleRef circle) {
CFStringRef circle_key = SOSCircleKeyCreateWithName(SOSCircleGetName(circle), NULL);
CFArrayAppendValue(keysToGet, circle_key);
CFReleaseNull(circle_key);
});
-
+
secnotice("updates", "***** EnsureFreshParameters *****");
SOSCloudKeychainSynchronizeAndWait(keysToGet, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef returnedValues, CFErrorRef sync_error) {
CFRetainSafe(valuesToUpdate);
success = true;
}
-
+
dispatch_semaphore_signal(wait_for);
dispatch_release(wait_for);
});
dispatch_semaphore_wait(wait_for, DISPATCH_TIME_FOREVER);
// TODO: Maybe we timeout here... used to dispatch_time(DISPATCH_TIME_NOW, 30ull * NSEC_PER_SEC));
dispatch_release(wait_for);
-
+
if ((valuesToUpdate) && (account)) {
if (!SOSAccountHandleUpdates(account, valuesToUpdate, error)) {
secerror("Freshness update failed: %@", *error);
-
+
success = false;
}
}
bool SOSCCSetUserCredentials_Server(CFStringRef user_label, CFDataRef user_password, CFErrorRef *error)
{
- return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
+ return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
if (!EnsureFreshParameters(account, block_error)) {
secnotice("updates", "EnsureFreshParameters error: %@", *block_error);
return false;
bool result = do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
return SOSAccountGetPrivateCredential(account, block_error) != NULL;
});
-
+
if (!result && error && *error && CFErrorGetDomain(*error) == kSOSErrorDomain) {
CFIndex code = CFErrorGetCode(*error);
if (code == kSOSErrorPrivateKeyAbsent || code == kSOSErrorPublicKeyAbsent) {
account_start_queue = dispatch_queue_create("init nis queue", DISPATCH_QUEUE_SERIAL);;
account_started = false;
});
-
+
__block bool done = false;
dispatch_sync(not_in_circle_queue, ^{
if (account_started) {
action();
}
});
-
+
if (!done && start_account) {
dispatch_sync(account_start_queue, ^{
__block bool do_start = false;
do_with_not_in_circle_bool_queue(true, ^{
result = sAccountInCircleCache;
});
-
+
return result;
#endif
}
void SOSCCSetThisDeviceDefinitelyNotActiveInCircle(SOSCCStatus currentStatus)
{
- bool active = !(currentStatus == kSOSCCCircleAbsent || currentStatus == kSOSCCNotInCircle);
- SOSCCCircleIsOn_SetArtifact(active);
+ SOSCCCircleIsOn_UpdateArtifact(currentStatus);
#if USE_BETTER
do_with_not_in_circle_bool_queue(false, ^{
sAccountInCircleCache = notActive;
SOSCCStatus SOSCCThisDeviceIsInCircle_Server(CFErrorRef *error)
{
__block SOSCCStatus status;
-
+
return do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
EnsureFreshParameters_once(account, NULL);
status = SOSAccountIsInCircles(account, block_error);
result = SOSAccountCopyApplicants(account, block_error);
return result != NULL;
});
-
+
return result;
}
CFArrayRef SOSCCCopyPeerPeerInfo_Server(CFErrorRef* error)
{
__block CFArrayRef result = NULL;
-
+
(void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
EnsureFreshParameters_once(account, NULL);
result = SOSAccountCopyPeers(account, block_error);
return result != NULL;
});
-
+
return result;
}
CFArrayRef SOSCCCopyConcurringPeerPeerInfo_Server(CFErrorRef* error)
{
__block CFArrayRef result = NULL;
-
+
(void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
EnsureFreshParameters_once(account, NULL);
result = SOSAccountCopyConcurringPeers(account, block_error);
return result != NULL;
});
-
+
return result;
}
CFStringRef SOSCCCopyIncompatibilityInfo_Server(CFErrorRef* error)
{
__block CFStringRef result = NULL;
-
+
(void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
EnsureFreshParameters_once(account, NULL);
result = SOSAccountCopyIncompatibilityInfo(account, block_error);
return result != NULL;
});
-
+
return result;
}
enum DepartureReason SOSCCGetLastDepartureReason_Server(CFErrorRef* error)
{
__block enum DepartureReason result = kSOSDepartureReasonError;
-
+
(void) do_with_account_if_after_first_unlock(error, ^bool (SOSAccountRef account, CFErrorRef* block_error) {
EnsureFreshParameters_once(account, NULL);
result = SOSAccountGetLastDepartureReason(account, block_error);
return result != kSOSDepartureReasonError;
});
-
+
return result;
}