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