KeychainSyncAccountNotification.m   [plain text]


//
//  KeychainSyncAccountNotification.m
//  Security
//

#import "KeychainSyncAccountNotification.h"
#import <Accounts/Accounts.h>
#import <Accounts/Accounts_Private.h>
#if TARGET_OS_IPHONE
#import <AppleAccount/ACAccount+AppleAccount.h>
#else
#import <AOSAccounts/ACAccount+iCloudAccount.h>
#endif
#import <AccountsDaemon/ACDAccountStore.h>
#import <Security/SecureObjectSync/SOSCloudCircle.h>
#if OCTAGON
#import <keychain/ot/OTControl.h>
#include <utilities/SecCFRelease.h>
#endif
#import "utilities/debugging.h"
#import "OT.h"

@implementation KeychainSyncAccountNotification

- (bool)accountIsPrimary:(ACAccount *)account
{
#if TARGET_OS_IPHONE
    return [account aa_isPrimaryAccount];
#else
    return [account icaIsPrimaryAccount];
#endif
}

// this is where we initialize SOS and OT for account sign-in
// the complement to this logic where we turn off SOS and OT is in KeychainDataclassOwner
// in the future we may bring this logic over there and delete KeychainSyncAccountNotification, but accounts people say that's a change that today would require coordination across multiple teams
// was asked to file this radar for accounts: <rdar://problem/40176124> Invoke DataclassOwner when enabling or signing into an account
- (BOOL)account:(ACAccount *)account willChangeWithType:(ACAccountChangeType)changeType inStore:(ACDAccountStore *)store oldAccount:(ACAccount *)oldAccount {

    if((changeType == kACAccountChangeTypeAdded) &&
       [account.accountType.identifier isEqualToString: ACAccountTypeIdentifierAppleAccount] &&
       [self accountIsPrimary:account]) {
#if OCTAGON
        if(SecOTIsEnabled()){
            __block NSError* error = nil;
            NSString *dsid = account.accountProperties[@"personID"];
            OTControl* otcontrol = [OTControl controlObject:&error];
            
            if (nil == otcontrol) {
                secerror("octagon: Failed to get OTControl: %@", error.localizedDescription);
            } else {
                dispatch_semaphore_t sema = dispatch_semaphore_create(0);
                
                [otcontrol signIn:dsid reply:^(BOOL result, NSError * _Nullable signedInError) {
                    if(!result || signedInError){
                        secerror("octagon: error signing in: %s", [[signedInError description] UTF8String]);
                    }
                    else{
                        secnotice("octagon", "signed into octagon trust");
                    }
                    dispatch_semaphore_signal(sema);
                    
                }];
                if (0 != dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60 * 5))) {
                    secerror("octagon: Timed out signing in");
                }
            }
        }else{
            secerror("Octagon not enabled!");
        }
#endif
    }

    if ((changeType == kACAccountChangeTypeDeleted) && [oldAccount.accountType.identifier isEqualToString:ACAccountTypeIdentifierAppleAccount]) {

        NSString *accountIdentifier = oldAccount.identifier;
        NSString *username = oldAccount.username;

        if(accountIdentifier != NULL && username !=NULL) {
            if ([self accountIsPrimary:oldAccount]) {
                CFErrorRef removalError = NULL;

                secinfo("accounts", "Performing SOS circle credential removal for account %@: %@", accountIdentifier, username);

                if (!SOSCCLoggedOutOfAccount(&removalError)) {
                    secerror("Account %@ could not leave the SOS circle: %@", accountIdentifier, removalError);
                }

            }
        }
    }

    
    return YES;
}

@end