5 // Created by Richard Murphy on 4/12/16.
9 #include "SOSAccountPriv.h"
10 #include "SOSAccountGhost.h"
11 #include <Security/SecureObjectSync/SOSPeerInfoCollections.h>
12 #include <Security/SecureObjectSync/SOSInternal.h>
13 #include <Security/SecureObjectSync/SOSAccount.h>
14 #include <Security/SecureObjectSync/SOSCircle.h>
15 #include <Security/SecureObjectSync/SOSPeerInfo.h>
16 #include <Security/SecureObjectSync/SOSPeerInfoV2.h>
18 #define DETECT_IOS_ONLY 1
20 static bool sosGhostCheckValid(SOSPeerInfoRef pi
) {
23 require_quiet(pi
, retOut
);
24 SOSPeerInfoDeviceClass peerClass
= SOSPeerInfoGetClass(pi
);
27 case SOSPeerInfo_tvOS
:
28 case SOSPeerInfo_watchOS
:
31 case SOSPeerInfo_macOS
:
32 case SOSPeerInfo_iCloud
:
33 case SOSPeerInfo_unknown
:
45 static CFSetRef
SOSCircleCreateGhostsOfPeerSet(SOSCircleRef circle
, SOSPeerInfoRef me
) {
46 CFMutableSetRef ghosts
= NULL
;
47 require_quiet(me
, errOut
);
48 require_quiet(sosGhostCheckValid(me
), errOut
);
49 require_quiet(circle
, errOut
);
50 require_quiet(SOSPeerInfoSerialNumberIsSet(me
), errOut
);
51 CFStringRef mySerial
= SOSPeerInfoCopySerialNumber(me
);
52 require_quiet(mySerial
, errOut
);
53 CFStringRef myPeerID
= SOSPeerInfoGetPeerID(me
);
54 ghosts
= CFSetCreateMutableForCFTypes(kCFAllocatorDefault
);
55 require_quiet(ghosts
, errOut1
);
56 SOSCircleForEachPeer(circle
, ^(SOSPeerInfoRef pi
) {
57 CFStringRef theirPeerID
= SOSPeerInfoGetPeerID(pi
);
58 if(!CFEqual(myPeerID
, theirPeerID
)) {
59 CFStringRef piSerial
= SOSPeerInfoCopySerialNumber(pi
);
60 if(CFEqualSafe(mySerial
, piSerial
)) {
61 CFSetAddValue(ghosts
, theirPeerID
);
63 CFReleaseNull(piSerial
);
67 CFReleaseNull(mySerial
);
73 static CFSetRef
SOSTrustedCircleCreateGhostsOfPeerSet(SOSAccountRef account
, SOSPeerInfoRef pi
) {
74 return (account
) ? SOSCircleCreateGhostsOfPeerSet(SOSAccountGetCircle(account
, NULL
), pi
): NULL
;
77 static CFSetRef
SOSTrustedCircleCopyGhostSet(SOSAccountRef account
) {
78 CFSetRef ghosts
= NULL
;
79 require_quiet(account
, errOut
);
80 SOSPeerInfoRef me
= SOSAccountGetMyPeerInfo(account
);
81 require_quiet(me
, errOut
);
82 require_quiet(sosGhostCheckValid(me
), errOut
);
83 ghosts
= SOSTrustedCircleCreateGhostsOfPeerSet(account
, me
);
89 static CFIndex
SOSTrustedCircleGhostSetCount(SOSAccountRef account
) {
91 CFSetRef ghosts
= SOSTrustedCircleCopyGhostSet(account
);
92 require_quiet(ghosts
, retOut
);
93 retval
= CFSetGetCount(ghosts
);
94 CFReleaseNull(ghosts
);
99 bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccountRef account
) {
100 return SOSTrustedCircleGhostSetCount(account
) == 0;
103 bool SOSAccountGhostResultsInReset(SOSAccountRef account
) {
104 return SOSTrustedCircleGhostSetCount(account
) == SOSCircleCountActivePeers(SOSAccountGetCircle(account
, NULL
));
108 // This only works if you're in the circle and have the private key
110 SOSCircleRef
SOSAccountCloneCircleWithoutMyGhosts(SOSAccountRef account
, SOSCircleRef startCircle
) {
111 SOSCircleRef newCircle
= NULL
;
112 CFSetRef ghosts
= NULL
;
113 require_quiet(account
, retOut
);
114 SecKeyRef userPrivKey
= SOSAccountGetPrivateCredential(account
, NULL
);
115 require_quiet(userPrivKey
, retOut
);
116 SOSFullPeerInfoRef meFull
= SOSAccountGetMyFullPeerInfo(account
);
117 require_quiet(meFull
, retOut
);
118 SOSPeerInfoRef me
= SOSFullPeerInfoGetPeerInfo(meFull
);
119 require_quiet(me
, retOut
);
120 bool iAmApplicant
= SOSCircleHasApplicant(startCircle
, me
, NULL
);
122 ghosts
= SOSCircleCreateGhostsOfPeerSet(startCircle
, me
);
123 require_quiet(ghosts
, retOut
);
124 require_quiet(CFSetGetCount(ghosts
), retOut
);
126 CFStringSetPerformWithDescription(ghosts
, ^(CFStringRef description
) {
127 secnotice("ghostbust", "Removing peers: %@", description
);
130 newCircle
= SOSCircleCopyCircle(kCFAllocatorDefault
, startCircle
, NULL
);
131 require_quiet(newCircle
, retOut
);
133 if(SOSCircleRemovePeersByIDUnsigned(newCircle
, ghosts
) && (SOSCircleCountPeers(newCircle
) == 0)) {
134 secnotice("resetToOffering", "Reset to offering with last ghost and me as applicant");
135 if(!SOSCircleResetToOffering(newCircle
, userPrivKey
, meFull
, NULL
) ||
136 !SOSAccountAddiCloudIdentity(account
, newCircle
, userPrivKey
, NULL
)) {
137 CFReleaseNull(newCircle
);
140 CFReleaseNull(newCircle
);
143 SOSCircleRemovePeersByID(newCircle
, userPrivKey
, meFull
, ghosts
, NULL
);
146 CFReleaseNull(ghosts
);