/ keychain / SecureObjectSync / SOSAccountTrustClassic+Retirement.m
SOSAccountTrustClassic+Retirement.m
  1  //
  2  //  SOSAccountTrustClassicRetirement.m
  3  //  Security
  4  //
  5  //  Created by Michelle Auricchio on 12/27/16.
  6  //
  7  //
  8  
  9  #import <Foundation/Foundation.h>
 10  #import "keychain/SecureObjectSync/SOSAccountTrustClassic.h"
 11  #import "keychain/SecureObjectSync/SOSAccountTrustClassic+Retirement.h"
 12  #import "keychain/SecureObjectSync/SOSPeerInfoCollections.h"
 13  #import "keychain/SecureObjectSync/SOSTransportMessageKVS.h"
 14  
 15  @implementation SOSAccountTrustClassic (Retirement)
 16  
 17  -(bool) cleanupRetirementTickets:(SOSAccount*)account circle:(SOSCircleRef)circle time:(size_t) seconds err:(CFErrorRef*) error
 18  {
 19      CFMutableSetRef retirees_to_remove = CFSetCreateMutableForSOSPeerInfosByID(kCFAllocatorDefault);
 20      
 21      __block bool success = true;
 22      
 23      CFSetForEach((__bridge CFSetRef)(self.retirees), ^(const void *value) {
 24          SOSPeerInfoRef retiree = (SOSPeerInfoRef) value;
 25          
 26          if (retiree) {
 27              // Remove the entry if it's not a retired peer or if it's retirment ticket has expired AND he's no longer in the circle.
 28              if (!SOSPeerInfoIsRetirementTicket(retiree) ||
 29                  (SOSPeerInfoRetireRetirementTicket(seconds, retiree) && !SOSCircleHasActivePeer(circle, retiree, NULL))) {
 30                  CFSetAddValue(retirees_to_remove, retiree);
 31              };
 32          }
 33      });
 34      
 35      CFMutableArrayRef retirees_to_cleanup = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
 36      CFSetForEach(retirees_to_remove, ^(const void *value) {
 37          CFArrayAppendValue(retirees_to_cleanup, value);
 38          CFSetRemoveValue((__bridge CFMutableSetRef)self.retirees, value);
 39      });
 40      
 41      CFReleaseNull(retirees_to_remove);
 42      
 43      CFDictionaryRef retirements_to_remove = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
 44                                                                           SOSCircleGetName(circle), retirees_to_cleanup,
 45                                                                           NULL);
 46      
 47      CFReleaseNull(retirees_to_cleanup);
 48      
 49      success = [account.circle_transport expireRetirementRecords:retirements_to_remove err:error];
 50  
 51      CFReleaseNull(retirements_to_remove);
 52      
 53      return success;
 54  }
 55  
 56  static inline CFMutableArrayRef CFDictionaryEnsureCFArrayAndGetCurrentValue(CFMutableDictionaryRef dict, CFTypeRef key)
 57  {
 58      CFMutableArrayRef result = (CFMutableArrayRef) CFDictionaryGetValue(dict, key);
 59      
 60      if (!isArray(result)) {
 61          result = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
 62          CFDictionarySetValue(dict, key, result);
 63          CFReleaseSafe(result);
 64      }
 65      
 66      return result;
 67  }
 68  
 69  
 70  -(bool) cleanupAfterPeer:(SOSMessageKVS*)kvsTransport circleTransport:(SOSCircleStorageTransport*)circleTransport seconds:(size_t) seconds circle:(SOSCircleRef) circle cleanupPeer:(SOSPeerInfoRef) cleanupPeer err:(CFErrorRef*) error
 71  {
 72      bool success = true;
 73      
 74      SOSPeerInfoRef myPeerInfo = self.peerInfo;
 75      require_action_quiet(self.fullPeerInfo && myPeerInfo, xit, SOSErrorCreate(kSOSErrorPeerNotFound, error, NULL, CFSTR("I have no peer")));
 76      require_quiet(SOSCircleHasActivePeer(circle, self.peerInfo, error), xit);
 77      
 78      CFStringRef cleanupPeerID = SOSPeerInfoGetPeerID(cleanupPeer);
 79  
 80      CFStringRef circle_name = SOSCircleGetName(circle);
 81      
 82      CFMutableDictionaryRef circleToPeerIDs = CFDictionaryCreateMutableForCFTypes(kCFAllocatorDefault);
 83      CFArrayAppendValue(CFDictionaryEnsureCFArrayAndGetCurrentValue(circleToPeerIDs, circle_name), cleanupPeerID);
 84      
 85      CFErrorRef localError = NULL;
 86      
 87      if (!(success &= [kvsTransport SOSTransportMessageCleanupAfterPeerMessages:kvsTransport peers:circleToPeerIDs err:&localError])) {
 88          secnotice("account", "Failed to cleanup after peer %@ messages: %@", cleanupPeerID, localError);
 89      }
 90      
 91      CFReleaseNull(localError);
 92      
 93      if((success &= SOSPeerInfoRetireRetirementTicket(seconds, cleanupPeer))) {
 94  
 95          if (!(success &= [circleTransport expireRetirementRecords:circleToPeerIDs err:&localError])) {
 96              secnotice("account", "Failed to cleanup after peer %@ retirement: %@", cleanupPeerID, localError);
 97          }
 98      }
 99      CFReleaseNull(localError);
100      CFReleaseNull(circleToPeerIDs);
101      
102  xit:
103      return success;
104  }
105  
106  @end