]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/SecureObjectSync/SOSAccountGhost.m
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / SecureObjectSync / SOSAccountGhost.m
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 #include <Security/SecureObjectSync/SOSAccountTrustClassic+Circle.h>
18
19 #define DETECT_IOS_ONLY 1
20
21 static bool sosGhostCheckValid(SOSPeerInfoRef pi) {
22 #if DETECT_IOS_ONLY
23 bool retval = false;
24 require_quiet(pi, retOut);
25 SOSPeerInfoDeviceClass peerClass = SOSPeerInfoGetClass(pi);
26 switch(peerClass) {
27 case SOSPeerInfo_iOS:
28 case SOSPeerInfo_tvOS:
29 case SOSPeerInfo_watchOS:
30 retval = true;
31 break;
32 case SOSPeerInfo_macOS:
33 case SOSPeerInfo_iCloud:
34 case SOSPeerInfo_unknown:
35 default:
36 retval = false;
37 break;
38 }
39 retOut:
40 return retval;
41 #else
42 return true;
43 #endif
44 }
45
46 static CFSetRef SOSCircleCreateGhostsOfPeerSet(SOSCircleRef circle, SOSPeerInfoRef me) {
47 CFMutableSetRef ghosts = NULL;
48 require_quiet(me, errOut);
49 require_quiet(sosGhostCheckValid(me), errOut);
50 require_quiet(circle, errOut);
51 require_quiet(SOSPeerInfoSerialNumberIsSet(me), errOut);
52 CFStringRef mySerial = SOSPeerInfoCopySerialNumber(me);
53 require_quiet(mySerial, errOut);
54 CFStringRef myPeerID = SOSPeerInfoGetPeerID(me);
55 ghosts = CFSetCreateMutableForCFTypes(kCFAllocatorDefault);
56 require_quiet(ghosts, errOut1);
57 SOSCircleForEachPeer(circle, ^(SOSPeerInfoRef pi) {
58 CFStringRef theirPeerID = SOSPeerInfoGetPeerID(pi);
59 if(!CFEqual(myPeerID, theirPeerID)) {
60 CFStringRef piSerial = SOSPeerInfoCopySerialNumber(pi);
61 if(CFEqualSafe(mySerial, piSerial)) {
62 CFSetAddValue(ghosts, theirPeerID);
63 }
64 CFReleaseNull(piSerial);
65 }
66 });
67 errOut1:
68 CFReleaseNull(mySerial);
69 errOut:
70 return ghosts;
71
72 }
73
74 static CFSetRef SOSTrustedCircleCreateGhostsOfPeerSet(SOSAccount* account, SOSPeerInfoRef pi) {
75 return (account) ? SOSCircleCreateGhostsOfPeerSet([account.trust getCircle:NULL], pi): NULL;
76 }
77
78 static CFSetRef SOSTrustedCircleCopyGhostSet(SOSAccount* account) {
79 CFSetRef ghosts = NULL;
80 require_quiet(account, errOut);
81 SOSPeerInfoRef me = account.peerInfo;
82 require_quiet(me, errOut);
83 require_quiet(sosGhostCheckValid(me), errOut);
84 ghosts = SOSTrustedCircleCreateGhostsOfPeerSet(account, me);
85 errOut:
86 return ghosts;
87
88 }
89
90 static CFIndex SOSTrustedCircleGhostSetCount(SOSAccount* account) {
91 CFIndex retval = 0;
92 CFSetRef ghosts = SOSTrustedCircleCopyGhostSet(account);
93 require_quiet(ghosts, retOut);
94 retval = CFSetGetCount(ghosts);
95 CFReleaseNull(ghosts);
96 retOut:
97 return retval;
98 }
99
100 bool SOSAccountTrustedCircleHasNoGhostOfMe(SOSAccount* account) {
101 return SOSTrustedCircleGhostSetCount(account) == 0;
102 }
103
104 bool SOSAccountGhostResultsInReset(SOSAccount* account) {
105 return SOSTrustedCircleGhostSetCount(account) == SOSCircleCountPeers([account.trust getCircle:NULL]);
106 }
107
108
109 // This only works if you're in the circle and have the private key
110
111 CF_RETURNS_RETAINED SOSCircleRef SOSAccountCloneCircleWithoutMyGhosts(SOSAccount* account, SOSCircleRef startCircle) {
112 SOSCircleRef newCircle = NULL;
113 CFSetRef ghosts = NULL;
114 require_quiet(account, retOut);
115 SecKeyRef userPrivKey = SOSAccountGetPrivateCredential(account, NULL);
116 require_quiet(userPrivKey, retOut);
117 SOSPeerInfoRef me = account.peerInfo;
118 require_quiet(me, retOut);
119 bool iAmApplicant = SOSCircleHasApplicant(startCircle, me, NULL);
120
121 ghosts = SOSCircleCreateGhostsOfPeerSet(startCircle, me);
122 require_quiet(ghosts, retOut);
123 require_quiet(CFSetGetCount(ghosts), retOut);
124
125 CFStringSetPerformWithDescription(ghosts, ^(CFStringRef description) {
126 secnotice("ghostbust", "Removing peers: %@", description);
127 });
128
129 newCircle = SOSCircleCopyCircle(kCFAllocatorDefault, startCircle, NULL);
130 require_quiet(newCircle, retOut);
131 if(iAmApplicant) {
132 if(SOSCircleRemovePeersByIDUnsigned(newCircle, ghosts) && (SOSCircleCountPeers(newCircle) == 0)) {
133 secnotice("resetToOffering", "Reset to offering with last ghost and me as applicant");
134 if(!SOSCircleResetToOffering(newCircle, userPrivKey, account.fullPeerInfo, NULL) ||
135 ![account.trust addiCloudIdentity:newCircle key:userPrivKey err:NULL]){
136 CFReleaseNull(newCircle);
137 }
138 account.notifyBackupOnExit = true;
139 } else {
140 CFReleaseNull(newCircle);
141 }
142 } else {
143 SOSCircleRemovePeersByID(newCircle, userPrivKey, account.fullPeerInfo, ghosts, NULL);
144 }
145 retOut:
146 CFReleaseNull(ghosts);
147 return newCircle;
148 }
149