2 // KeychainSyncAccountNotification.m
6 #import "KeychainSyncAccountNotification.h"
7 #import <Accounts/Accounts.h>
8 #import <Accounts/Accounts_Private.h>
9 #import <AppleAccount/ACAccount+AppleAccount.h>
10 #import <AccountsDaemon/ACDAccountStore.h>
11 #import <Security/SecureObjectSync/SOSCloudCircle.h>
12 #import <AuthKit/AuthKit.h>
13 #import <AuthKit/AuthKit_Private.h>
15 #import <keychain/ot/OTControl.h>
16 #include <utilities/SecCFRelease.h>
18 #import "utilities/debugging.h"
21 @implementation KeychainSyncAccountNotification
23 - (bool)accountIsPrimary:(ACAccount *)account
25 return [account aa_isAccountClass:AAAccountClassPrimary];
28 // this is where we initialize SOS and OT for account sign-in
29 // in the future we may bring this logic over to KeychainDataclassOwner and delete KeychainSyncAccountNotification, but accounts people say that's a change that today would require coordination across multiple teams
30 // was asked to file this radar for accounts: <rdar://problem/40176124> Invoke DataclassOwner when enabling or signing into an account
31 - (void)account:(ACAccount *)account didChangeWithType:(ACAccountChangeType)changeType inStore:(ACDAccountStore *)store oldAccount:(ACAccount *)oldAccount {
33 if((changeType == kACAccountChangeTypeAdded || changeType == kACAccountChangeTypeModified || changeType == kACAccountChangeTypeWarmingUp) &&
34 [account.accountType.identifier isEqualToString: ACAccountTypeIdentifierAppleAccount] &&
35 [self accountIsPrimary:account]) {
37 SOSCCLoggedIntoAccount(NULL);
40 if(OctagonIsEnabled()){
41 NSString* altDSID = [account aa_altDSID];
42 secnotice("octagon-account", "Received an primary Apple account modification (altDSID %@)", altDSID);
44 __block NSError* error = nil;
46 // Use asynchronous XPC here for speed and just hope it works
47 OTControl* otcontrol = [OTControl controlObject:false error:&error];
49 if (nil == otcontrol) {
50 secerror("octagon-account: Failed to get OTControl: %@", error.localizedDescription);
52 [otcontrol signIn:altDSID container:nil context:OTDefaultContext reply:^(NSError * _Nullable signedInError) {
53 // take a retain on otcontrol so it won't invalidate the connection
57 secerror("octagon-account: error signing in: %s", [[signedInError description] UTF8String]);
59 secnotice("octagon-account", "account now signed in for octagon operation");
64 secerror("Octagon not enabled; not signing in");
69 // If there is any change to any AuthKit account's security level, notify octagon
72 if([account.accountType.identifier isEqualToString: ACAccountTypeIdentifierIDMS]) {
73 NSString* altDSID = [account aa_altDSID];;
74 secnotice("octagon-authkit", "Received an IDMS account modification (altDSID: %@)", altDSID);
76 AKAccountManager *manager = [AKAccountManager sharedInstance];
78 AKAppleIDSecurityLevel oldSecurityLevel = [manager securityLevelForAccount:oldAccount];
79 AKAppleIDSecurityLevel newSecurityLevel = [manager securityLevelForAccount:account];
81 if(oldSecurityLevel != newSecurityLevel) {
82 secnotice("octagon-authkit", "IDMS security level has now moved to %ld for altDSID %@", (unsigned long)newSecurityLevel, altDSID);
84 __block NSError* error = nil;
85 // Use an asynchronous otcontrol for Speed But Not Necessarily Correctness
86 OTControl* otcontrol = [OTControl controlObject:false error:&error];
87 if(!otcontrol || error) {
88 secerror("octagon-authkit: Failed to get OTControl: %@", error);
90 [otcontrol notifyIDMSTrustLevelChangeForContainer:nil context:OTDefaultContext reply:^(NSError * _Nullable idmsError) {
91 // take a retain on otcontrol so it won't invalidate the connection
95 secerror("octagon-authkit: error with idms trust level change in: %s", [[idmsError description] UTF8String]);
97 secnotice("octagon-authkit", "informed octagon of IDMS trust level change");
103 secnotice("octagon-authkit", "No change to IDMS security level (%lu) for altDSID %@", (unsigned long)newSecurityLevel, altDSID);
108 if ((changeType == kACAccountChangeTypeDeleted) && [oldAccount.accountType.identifier isEqualToString:ACAccountTypeIdentifierAppleAccount]) {
109 NSString* altDSID = [oldAccount aa_altDSID];
110 secnotice("octagon-account", "Received an Apple account deletion (altDSID %@)", altDSID);
112 NSString *accountIdentifier = oldAccount.identifier;
113 NSString *username = oldAccount.username;
115 if(accountIdentifier != NULL && username !=NULL) {
116 if ([self accountIsPrimary:oldAccount]) {
117 CFErrorRef removalError = NULL;
119 secinfo("accounts", "Performing SOS circle credential removal for account %@: %@", accountIdentifier, username);
121 if (!SOSCCLoggedOutOfAccount(&removalError)) {
122 secerror("Account %@ could not leave the SOS circle: %@", accountIdentifier, removalError);
126 if(OctagonIsEnabled()){
127 __block NSError* error = nil;
129 // Use an asynchronous control for Speed
130 OTControl* otcontrol = [OTControl controlObject:false error:&error];
132 if (nil == otcontrol) {
133 secerror("octagon-account: Failed to get OTControl: %@", error.localizedDescription);
135 [otcontrol signOut:nil context:OTDefaultContext reply:^(NSError * _Nullable signedInError) {
136 // take a retain on otcontrol so it won't invalidate the connection
140 secerror("octagon-account: error signing out: %s", [[signedInError description] UTF8String]);
142 secnotice("octagon-account", "signed out of octagon trust");
147 secerror("Octagon not enabled; not signing out");