7 #import <Foundation/Foundation.h>
 
   8 #import "SOSAuthKitHelpers.h"
 
   9 #import <utilities/debugging.h>
 
  10 #import "keychain/SecureObjectSync/SOSAccount.h"
 
  11 #import "keychain/SecureObjectSync/SOSAccountPriv.h"
 
  12 #import "keychain/SecureObjectSync/SOSFullPeerInfo.h"
 
  13 #import "keychain/SecureObjectSync/SOSPeerInfoV2.h"
 
  14 #import "keychain/SecureObjectSync/SOSPeerInfoPriv.h"
 
  16 #if !TARGET_OS_BRIDGE && !TARGET_OS_SIMULATOR && __OBJC2__
 
  17 #import <AppleAccount/AppleAccount_Private.h>
 
  18 #import <AuthKit/AuthKit.h>
 
  19 #import <AuthKit/AuthKit_Private.h>
 
  20 #import <SoftLinking/SoftLinking.h>
 
  24 SOFT_LINK_FRAMEWORK(PrivateFrameworks, AuthKit);
 
  25 SOFT_LINK_FRAMEWORK(Frameworks, Accounts);
 
  27 #pragma clang diagnostic push
 
  28 #pragma clang diagnostic ignored "-Wstrict-prototypes"
 
  29 SOFT_LINK_CLASS(AuthKit, AKAccountManager);
 
  30 SOFT_LINK_CLASS(AuthKit, AKAnisetteProvisioningController);
 
  31 SOFT_LINK_CLASS(AuthKit, AKAppleIDAuthenticationController);
 
  32 SOFT_LINK_CLASS(AuthKit, AKDeviceListRequestContext);
 
  33 SOFT_LINK_CLASS(Accounts, Accounts);
 
  34 SOFT_LINK_CLASS(Accounts, ACAccountStore);
 
  35 SOFT_LINK_CONSTANT(AuthKit, AKServiceNameiCloud, const NSString *);
 
  36 #pragma clang diagnostic pop
 
  38 static void *accountsFramework = NULL;
 
  39 static void *appleAccountFramework = NULL;
 
  42 initAccountsFramework(void) {
 
  43     static dispatch_once_t onceToken;
 
  44     dispatch_once(&onceToken, ^{
 
  45         accountsFramework = dlopen("/System/Library/Frameworks/Accounts.framework/Accounts", RTLD_LAZY);
 
  46         appleAccountFramework = dlopen("/System/Library/PrivateFrameworks/AppleAccount.framework/AppleAccount", RTLD_LAZY);
 
  50 @implementation SOSAuthKitHelpers
 
  52 @class SOSAuthKitHelpers;
 
  54 + (NSString *) machineID {
 
  56     NSString *retval = nil;
 
  57     secnotice("sosauthkit", "Entering machineID");
 
  59     AKAnisetteProvisioningController *anisetteController = [getAKAnisetteProvisioningControllerClass() new];
 
  60     if(anisetteController) {
 
  61         AKAnisetteData *anisetteData = [anisetteController anisetteDataWithError:&error];
 
  63             retval = [anisetteData.machineID copy];
 
  65                 secnotice("sosauthkit", "machineID is %@", retval);
 
  67                 secnotice("sosauthkit", "Failed to get machineID");
 
  70             secnotice("sosauthkit", "can't get mID: %@", error);
 
  73         secnotice("sosauthkit", "can't get controller");
 
  78 static ACAccount *GetPrimaryAccount(void) {
 
  79     ACAccount *primaryAccount;
 
  81     initAccountsFramework();
 
  83     ACAccountStore *store = [getACAccountStoreClass() new];
 
  86         secnotice("sosauthkit", "can't get store");
 
  90     primaryAccount = [store aa_primaryAppleAccount];
 
  92     return primaryAccount;
 
  96 + (void)activeMIDs:(void(^_Nonnull)(NSSet <SOSTrustedDeviceAttributes *> *activeMIDs, NSError *error))complete {
 
  97     ACAccount *primaryAccount;
 
  98     AKDeviceListRequestContext *context;
 
 100     primaryAccount = GetPrimaryAccount();
 
 102     if(!primaryAccount) {
 
 103         secnotice("sosauthkit", "can't get account");
 
 104         complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"no primary account"}]);
 
 108     context = [getAKDeviceListRequestContextClass() new];
 
 109     if (context == NULL) {
 
 110         complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"can't get AKDeviceListRequestContextClass"}]);
 
 113     context.altDSID = primaryAccount.aa_altDSID;
 
 114     context.services = @[ getAKServiceNameiCloud() ];
 
 116     // -[AKAppleIDAuthenticationController fetchDeviceListWithContext:error:] is not exposed, use a semaphore
 
 117     AKAppleIDAuthenticationController *authController = [getAKAppleIDAuthenticationControllerClass() new];
 
 118     if(!authController) {
 
 119         complete(NULL, [NSError errorWithDomain:(__bridge NSString *)kSecErrorDomain code:errSecParam userInfo:@{NSLocalizedDescriptionKey : @"can't get authController"}]);
 
 123     [authController fetchDeviceListWithContext:context completion:^(NSArray<AKRemoteDevice *> *deviceList, NSError *error) {
 
 124         NSMutableSet *mids = [NSMutableSet new];
 
 125         for(AKRemoteDevice *akdev in deviceList) {
 
 126             SOSTrustedDeviceAttributes *newdev = [SOSTrustedDeviceAttributes new];
 
 127             newdev.machineID = akdev.machineId;
 
 128             newdev.serialNumber = akdev.serialNumber;
 
 129             [mids addObject:newdev];
 
 131         if([mids count] == 0) {
 
 132             secnotice("sosauthkit", "found no devices in account");
 
 135         complete(mids, error);
 
 139 + (bool) peerinfoHasMID: (SOSAccount *) account {
 
 140     SOSPeerInfoRef pi = SOSFullPeerInfoGetPeerInfo(account.fullPeerInfo);
 
 141     if(!pi) return true;  // if there's no PI then just say "we don't need one"
 
 142     return SOSPeerInfoV2DictionaryHasString(pi, sMachineIDKey);
 
 147 + (bool) updateMIDInPeerInfo: (SOSAccount *) account {
 
 148     NSString *mid = [SOSAuthKitHelpers machineID];
 
 149     if(!mid) return true;
 
 150     CFErrorRef error = NULL;
 
 151     SOSAccountSetValue(account, sMachineIDKey, (__bridge CFStringRef)mid, &error);
 
 152     bool peerUpdated = SOSAccountUpdatePeerInfoAndPush(account, CFSTR("Add Machine ID"), &error, ^bool(SOSPeerInfoRef pi, CFErrorRef *error) {
 
 153         if(SOSPeerInfoV2DictionaryHasString(pi, sMachineIDKey)) {
 
 156         secnotice("sosauthkit", "Setting PeerInfo MID to %@", mid);
 
 157         SOSPeerInfoV2DictionarySetValue(pi, sMachineIDKey, (__bridge CFStringRef)mid);
 
 161         secnotice("sosauthkit", "Failed to record MID in PeerInfo: %@", error);
 
 163     CFReleaseNull(error);
 
 168 + (bool) accountIsHSA2 {
 
 171     ACAccount *primaryAccount = GetPrimaryAccount();
 
 172     AKAccountManager *manager = [getAKAccountManagerClass() new];
 
 174     if(manager && primaryAccount) {
 
 175         ACAccount *account = [manager authKitAccountWithAltDSID:[manager altDSIDForAccount:primaryAccount]];
 
 176         AKAppleIDSecurityLevel securityLevel = [manager securityLevelForAccount:account];
 
 177         if(securityLevel == AKAppleIDSecurityLevelHSA2) {
 
 180             secnotice("sosauthkit", "Security level is %lu", (unsigned long)securityLevel);
 
 182         secnotice("sosauthkit", "Account %s HSA2", (hsa2) ? "is": "isn't" );
 
 184         secnotice("sosauthkit", "Failed to get manager");
 
 190 -(id) initWithActiveMIDS: (NSSet <SOSTrustedDeviceAttributes *> *) theMidList
 
 196     NSMutableSet *MmachineIDs = [[NSMutableSet alloc] init];
 
 197     NSMutableSet *MserialNumbers = [[NSMutableSet alloc] init];
 
 198     _machineIDs = [[NSSet alloc] init];
 
 199     _serialNumbers = [[NSSet alloc] init];
 
 201     if(!theMidList) return nil;
 
 202     _midList = theMidList;
 
 204     for(SOSTrustedDeviceAttributes *dev in _midList) {
 
 206             [MmachineIDs addObject:dev.machineID];
 
 208         if(dev.serialNumber) {
 
 209             [MserialNumbers addObject:dev.serialNumber];
 
 213     _machineIDs = MmachineIDs;
 
 214     _serialNumbers = MserialNumbers;
 
 218 // if the ID passed in is null, the peer doesn't have one, we'll say true - we can't tell from the list
 
 219 - (bool) midIsValidInList: (NSString *) machineId {
 
 220     return (machineId) ? [_machineIDs containsObject:machineId]: true;
 
 223 - (bool) serialIsValidInList: (NSString *) serialNumber {
 
 224     return (serialNumber) ? [_serialNumbers containsObject:serialNumber]: true;
 
 228     return [ _machineIDs count ] > 0;
 
 234 @implementation SOSAuthKitHelpers
 
 236 @class SOSAuthKitHelpers;
 
 238 + (NSString *) machineID {
 
 242 + (void)activeMIDs:(void(^_Nonnull)(NSSet<SOSTrustedDeviceAttributes*> *activeMIDs, NSError *error))complete {
 
 246 + (bool) updateMIDInPeerInfo: (SOSAccount *) account {
 
 250 + (bool) peerinfoHasMID: (SOSAccount *) account {
 
 254 + (bool) accountIsHSA2 {
 
 258 - (id _Nullable) initWithActiveMIDS: (NSSet *_Nullable) theMidList {
 
 262 - (bool) midIsValidInList: (NSString *_Nullable) machineId {
 
 266 - (bool) serialIsValidInList: (NSString *_Nullable) serialNumber {