X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b04fe171f0375ecd5d8a24747ca1dff85720a0ca..6b200bc335dc93c5516ccb52f14bd896d8c7fad7:/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c?ds=inline diff --git a/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c new file mode 100644 index 00000000..bfcce031 --- /dev/null +++ b/OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c @@ -0,0 +1,149 @@ +// +// SOSAccountGhost.c +// sec +// +// Created by Richard Murphy on 4/12/16. +// +// + +#include "SOSAccountPriv.h" +#include "SOSAccountGhost.h" +#include +#include +#include +#include +#include +#include + +#define DETECT_IOS_ONLY 1 + +static bool sosGhostCheckValid(SOSPeerInfoRef pi) { +#if DETECT_IOS_ONLY + bool retval = false; + require_quiet(pi, retOut); + SOSPeerInfoDeviceClass peerClass = SOSPeerInfoGetClass(pi); + switch(peerClass) { + case SOSPeerInfo_iOS: + case SOSPeerInfo_tvOS: + case SOSPeerInfo_watchOS: + retval = true; + break; + case SOSPeerInfo_macOS: + case SOSPeerInfo_iCloud: + case SOSPeerInfo_unknown: + default: + retval = false; + break; + } +retOut: + return retval; +#else + return true; +#endif +} + +static CFSetRef SOSCircleCreateGhostsOfPeerSet(SOSCircleRef circle, SOSPeerInfoRef me) { + CFMutableSetRef ghosts = NULL; + require_quiet(me, errOut); + require_quiet(sosGhostCheckValid(me), errOut); + require_quiet(circle, errOut); + require_quiet(SOSPeerInfoSerialNumberIsSet(me), errOut); + CFStringRef mySerial = SOSPeerInfoCopySerialNumber(me); + require_quiet(mySerial, errOut); + CFStringRef myPeerID = SOSPeerInfoGetPeerID(me); + ghosts = CFSetCreateMutableForCFTypes(kCFAllocatorDefault); + require_quiet(ghosts, errOut1); + SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef pi) { + CFStringRef theirPeerID = SOSPeerInfoGetPeerID(pi); + if(!CFEqual(myPeerID, theirPeerID)) { + CFStringRef piSerial = SOSPeerInfoCopySerialNumber(pi); + if(CFEqualSafe(mySerial, piSerial)) { + CFSetAddValue(ghosts, theirPeerID); + } + CFReleaseNull(piSerial); + } + }); +errOut1: + CFReleaseNull(mySerial); +errOut: + return ghosts; + +} + +static CFSetRef SOSTrustedCircleCreateGhostsOfPeerSet(SOSAccountRef account, SOSPeerInfoRef pi) { + return (account) ? SOSCircleCreateGhostsOfPeerSet(SOSAccountGetCircle(account, NULL), pi): NULL; +} + +static CFSetRef SOSTrustedCircleCopyGhostSet(SOSAccountRef account) { + CFSetRef ghosts = NULL; + require_quiet(account, errOut); + SOSPeerInfoRef me = SOSAccountGetMyPeerInfo(account); + require_quiet(me, errOut); + require_quiet(sosGhostCheckValid(me), errOut); + ghosts = SOSTrustedCircleCreateGhostsOfPeerSet(account, me); +errOut: + return ghosts; + +} + +static CFIndex SOSTrustedCircleGhostSetCount(SOSAccountRef account) { + CFIndex retval = 0; + CFSetRef ghosts = SOSTrustedCircleCopyGhostSet(account); + require_quiet(ghosts, retOut); + retval = CFSetGetCount(ghosts); + CFReleaseNull(ghosts); +retOut: + return retval; +} + +bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccountRef account) { + return SOSTrustedCircleGhostSetCount(account) == 0; +} + +bool SOSAccountGhostResultsInReset(SOSAccountRef account) { + return SOSTrustedCircleGhostSetCount(account) == SOSCircleCountActivePeers(SOSAccountGetCircle(account, NULL)); +} + + +// This only works if you're in the circle and have the private key + +SOSCircleRef SOSAccountCloneCircleWithoutMyGhosts(SOSAccountRef account, SOSCircleRef startCircle) { + SOSCircleRef newCircle = NULL; + CFSetRef ghosts = NULL; + require_quiet(account, retOut); + SecKeyRef userPrivKey = SOSAccountGetPrivateCredential(account, NULL); + require_quiet(userPrivKey, retOut); + SOSFullPeerInfoRef meFull = SOSAccountGetMyFullPeerInfo(account); + require_quiet(meFull, retOut); + SOSPeerInfoRef me = SOSFullPeerInfoGetPeerInfo(meFull); + require_quiet(me, retOut); + bool iAmApplicant = SOSCircleHasApplicant(startCircle, me, NULL); + + ghosts = SOSCircleCreateGhostsOfPeerSet(startCircle, me); + require_quiet(ghosts, retOut); + require_quiet(CFSetGetCount(ghosts), retOut); + + CFStringSetPerformWithDescription(ghosts, ^(CFStringRef description) { + secnotice("ghostbust", "Removing peers: %@", description); + }); + + newCircle = SOSCircleCopyCircle(kCFAllocatorDefault, startCircle, NULL); + require_quiet(newCircle, retOut); + if(iAmApplicant) { + if(SOSCircleRemovePeersByIDUnsigned(newCircle, ghosts) && (SOSCircleCountPeers(newCircle) == 0)) { + secnotice("resetToOffering", "Reset to offering with last ghost and me as applicant"); + if(!SOSCircleResetToOffering(newCircle, userPrivKey, meFull, NULL) || + !SOSAccountAddiCloudIdentity(account, newCircle, userPrivKey, NULL)) { + CFReleaseNull(newCircle); + } + } else { + CFReleaseNull(newCircle); + } + } else { + SOSCircleRemovePeersByID(newCircle, userPrivKey, meFull, ghosts, NULL); + } +retOut: + CFReleaseNull(ghosts); + return newCircle; +} +