]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.c
bfcce03107115c1cd058f58a9e2d4e5234eb3690
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountGhost.c
1 //
2 // SOSAccountGhost.c
3 // sec
4 //
5 // Created by Richard Murphy on 4/12/16.
6 //
7 //
8
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>
17
18 #define DETECT_IOS_ONLY 1
19
20 static bool sosGhostCheckValid(SOSPeerInfoRef pi) {
21 #if DETECT_IOS_ONLY
22 bool retval = false;
23 require_quiet(pi, retOut);
24 SOSPeerInfoDeviceClass peerClass = SOSPeerInfoGetClass(pi);
25 switch(peerClass) {
26 case SOSPeerInfo_iOS:
27 case SOSPeerInfo_tvOS:
28 case SOSPeerInfo_watchOS:
29 retval = true;
30 break;
31 case SOSPeerInfo_macOS:
32 case SOSPeerInfo_iCloud:
33 case SOSPeerInfo_unknown:
34 default:
35 retval = false;
36 break;
37 }
38 retOut:
39 return retval;
40 #else
41 return true;
42 #endif
43 }
44
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);
62 }
63 CFReleaseNull(piSerial);
64 }
65 });
66 errOut1:
67 CFReleaseNull(mySerial);
68 errOut:
69 return ghosts;
70
71 }
72
73 static CFSetRef SOSTrustedCircleCreateGhostsOfPeerSet(SOSAccountRef account, SOSPeerInfoRef pi) {
74 return (account) ? SOSCircleCreateGhostsOfPeerSet(SOSAccountGetCircle(account, NULL), pi): NULL;
75 }
76
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);
84 errOut:
85 return ghosts;
86
87 }
88
89 static CFIndex SOSTrustedCircleGhostSetCount(SOSAccountRef account) {
90 CFIndex retval = 0;
91 CFSetRef ghosts = SOSTrustedCircleCopyGhostSet(account);
92 require_quiet(ghosts, retOut);
93 retval = CFSetGetCount(ghosts);
94 CFReleaseNull(ghosts);
95 retOut:
96 return retval;
97 }
98
99 bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccountRef account) {
100 return SOSTrustedCircleGhostSetCount(account) == 0;
101 }
102
103 bool SOSAccountGhostResultsInReset(SOSAccountRef account) {
104 return SOSTrustedCircleGhostSetCount(account) == SOSCircleCountActivePeers(SOSAccountGetCircle(account, NULL));
105 }
106
107
108 // This only works if you're in the circle and have the private key
109
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);
121
122 ghosts = SOSCircleCreateGhostsOfPeerSet(startCircle, me);
123 require_quiet(ghosts, retOut);
124 require_quiet(CFSetGetCount(ghosts), retOut);
125
126 CFStringSetPerformWithDescription(ghosts, ^(CFStringRef description) {
127 secnotice("ghostbust", "Removing peers: %@", description);
128 });
129
130 newCircle = SOSCircleCopyCircle(kCFAllocatorDefault, startCircle, NULL);
131 require_quiet(newCircle, retOut);
132 if(iAmApplicant) {
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);
138 }
139 } else {
140 CFReleaseNull(newCircle);
141 }
142 } else {
143 SOSCircleRemovePeersByID(newCircle, userPrivKey, meFull, ghosts, NULL);
144 }
145 retOut:
146 CFReleaseNull(ghosts);
147 return newCircle;
148 }
149