]>
Commit | Line | Data |
---|---|---|
fa7225c8 A |
1 | // |
2 | // SOSAccountTransaction.c | |
3 | // sec | |
4 | // | |
5 | // | |
6 | ||
7 | #include "SOSAccountTransaction.h" | |
8 | ||
9 | #include <utilities/SecCFWrappers.h> | |
10 | #include <CoreFoundation/CoreFoundation.h> | |
11 | ||
12 | #include <Security/SecureObjectSync/SOSAccount.h> | |
13 | #include <Security/SecureObjectSync/SOSAccountPriv.h> | |
14 | #include <Security/SecureObjectSync/SOSPeerInfoV2.h> | |
15 | #include <Security/SecureObjectSync/SOSTransport.h> | |
16 | #include <Security/SecureObjectSync/SOSTransportCircle.h> | |
17 | ||
18 | #define kPublicKeyNotAvailable "com.apple.security.publickeynotavailable" | |
19 | ||
20 | CFGiblisFor(SOSAccountTransaction); | |
21 | ||
22 | static void SOSAccountTransactionDestroy(CFTypeRef aObj) { | |
23 | SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj; | |
24 | ||
25 | CFReleaseNull(at->initialUnsyncedViews); | |
26 | CFReleaseNull(at->initialID); | |
27 | CFReleaseNull(at->account); | |
28 | CFReleaseNull(at->initialViews); | |
29 | CFReleaseNull(at->initialKeyParameters); | |
30 | } | |
31 | ||
32 | static CFStringRef SOSAccountTransactionCopyFormatDescription(CFTypeRef aObj, CFDictionaryRef formatOptions) { | |
33 | SOSAccountTransactionRef at = (SOSAccountTransactionRef) aObj; | |
34 | ||
35 | CFMutableStringRef description = CFStringCreateMutable(kCFAllocatorDefault, 0); | |
36 | ||
37 | CFStringAppendFormat(description, NULL, CFSTR("<SOSAccountTransactionRef@%p %ld>"), | |
38 | at, at->initialViews ? CFSetGetCount(at->initialViews) : 0); | |
39 | ||
40 | return description; | |
41 | } | |
42 | ||
43 | static void SOSAccountTransactionRestart(SOSAccountTransactionRef txn) { | |
44 | txn->initialInCircle = SOSAccountIsInCircle(txn->account, NULL); | |
45 | ||
46 | if(txn->account) | |
47 | txn->initialTrusted = (txn->account)->user_public_trusted; | |
48 | ||
49 | if (txn->initialInCircle) { | |
50 | SOSAccountEnsureSyncChecking(txn->account); | |
51 | } | |
52 | ||
53 | CFAssignRetained(txn->initialUnsyncedViews, SOSAccountCopyOutstandingViews(txn->account)); | |
54 | ||
55 | CFReleaseNull(txn->initialKeyParameters); | |
56 | ||
57 | if(txn->account && txn->account->user_key_parameters){ | |
58 | CFReleaseNull(txn->initialKeyParameters); | |
59 | txn->initialKeyParameters = CFDataCreateCopy(kCFAllocatorDefault, txn->account->user_key_parameters); | |
60 | } | |
61 | SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account); | |
62 | CFAssignRetained(txn->initialViews, mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL); | |
63 | ||
64 | CFRetainAssign(txn->initialID, SOSPeerInfoGetPeerID(mpi)); | |
65 | ||
66 | CFStringSetPerformWithDescription(txn->initialViews, ^(CFStringRef description) { | |
67 | secnotice("acct-txn", "Starting as:%s v:%@", txn->initialInCircle ? "member" : "non-member", description); | |
68 | }); | |
69 | } | |
70 | ||
71 | ||
72 | SOSAccountTransactionRef SOSAccountTransactionCreate(SOSAccountRef account) { | |
73 | SOSAccountTransactionRef at = CFTypeAllocate(SOSAccountTransaction, struct __OpaqueSOSAccountTransaction, kCFAllocatorDefault); | |
74 | ||
75 | at->account = CFRetainSafe(account); | |
76 | ||
77 | at->initialInCircle = false; | |
78 | at->initialViews = NULL; | |
79 | at->initialKeyParameters = NULL; | |
80 | at->initialTrusted = false; | |
81 | at->initialUnsyncedViews = NULL; | |
82 | at->initialID = NULL; | |
83 | ||
84 | SOSAccountTransactionRestart(at); | |
85 | ||
86 | return at; | |
87 | } | |
88 | ||
89 | #define ACCOUNT_STATE_INTERVAL 20 | |
90 | ||
91 | void SOSAccountTransactionFinish(SOSAccountTransactionRef txn) { | |
92 | CFErrorRef localError = NULL; | |
93 | bool notifyEngines = false; | |
94 | static int do_account_state_at_zero = 0; | |
95 | ||
96 | SOSPeerInfoRef mpi = SOSAccountGetMyPeerInfo(txn->account); | |
97 | ||
98 | bool inCircle = SOSAccountIsInCircle(txn->account, NULL); | |
99 | ||
100 | if (inCircle) { | |
101 | SOSAccountEnsureSyncChecking(txn->account); | |
102 | } else { | |
103 | SOSAccountCancelSyncChecking(txn->account); | |
104 | } | |
105 | ||
106 | // If our identity changed our inital set should be everything. | |
107 | if (!CFEqualSafe(txn->initialID, SOSPeerInfoGetPeerID(mpi))) { | |
108 | CFAssignRetained(txn->initialUnsyncedViews, SOSViewCopyViewSet(kViewSetAll)); | |
109 | } | |
110 | ||
111 | CFSetRef finalUnsyncedViews = SOSAccountCopyOutstandingViews(txn->account); | |
112 | if (!CFEqualSafe(txn->initialUnsyncedViews, finalUnsyncedViews)) { | |
113 | if (SOSAccountHandleOutOfSyncUpdate(txn->account, txn->initialUnsyncedViews, finalUnsyncedViews)) { | |
114 | notifyEngines = true; | |
115 | } | |
116 | ||
117 | CFStringSetPerformWithDescription(txn->initialUnsyncedViews, ^(CFStringRef newUnsyncedDescripion) { | |
118 | CFStringSetPerformWithDescription(finalUnsyncedViews, ^(CFStringRef unsyncedDescription) { | |
119 | secnotice("initial-sync", "Unsynced was: %@", unsyncedDescription); | |
120 | secnotice("initial-sync", "Unsynced is: %@", newUnsyncedDescripion); | |
121 | }); | |
122 | }); | |
123 | } | |
124 | CFReleaseNull(finalUnsyncedViews); | |
125 | ||
126 | if (txn->account->engine_peer_state_needs_repair) { | |
127 | // We currently only get here from a failed syncwithallpeers, so | |
128 | // that will retry. If this logic changes, force a syncwithallpeers | |
129 | if (!SOSAccountEnsurePeerRegistration(txn->account, &localError)) { | |
130 | secerror("Ensure peer registration while repairing failed: %@", localError); | |
131 | } | |
132 | CFReleaseNull(localError); | |
133 | ||
134 | notifyEngines = true; | |
135 | } | |
136 | ||
137 | if(txn->account->circle_rings_retirements_need_attention){ | |
138 | SOSAccountRecordRetiredPeersInCircle(txn->account); | |
139 | ||
140 | SOSAccountEnsureInBackupRings(txn->account); | |
141 | ||
142 | CFErrorRef localError = NULL; | |
143 | if(!SOSTransportCircleFlushChanges(txn->account->circle_transport, &localError)) { | |
144 | secerror("flush circle failed %@", localError); | |
145 | } | |
146 | CFReleaseSafe(localError); | |
147 | ||
148 | notifyEngines = true; | |
149 | } | |
150 | ||
151 | if (notifyEngines) { | |
152 | SOSAccountNotifyEngines(txn->account); | |
153 | } | |
154 | ||
155 | if(txn->account->key_interests_need_updating){ | |
156 | SOSUpdateKeyInterest(txn->account); | |
157 | } | |
158 | ||
159 | txn->account->key_interests_need_updating = false; | |
160 | txn->account->circle_rings_retirements_need_attention = false; | |
161 | txn->account->engine_peer_state_needs_repair = false; | |
162 | ||
163 | SOSAccountFlattenToSaveBlock(txn->account); | |
164 | ||
165 | // Check for firing view membership change. On change of view membership or circle membership | |
166 | bool isInCircle = SOSAccountIsInCircle(txn->account, NULL); | |
167 | ||
168 | mpi = SOSAccountGetMyPeerInfo(txn->account); | |
169 | CFSetRef views = mpi ? SOSPeerInfoCopyEnabledViews(mpi) : NULL; | |
170 | ||
171 | CFStringSetPerformWithDescription(views, ^(CFStringRef description) { | |
172 | secnotice("acct-txn", "Finished as:%s v:%@", isInCircle ? "member" : "non-member", description); | |
173 | }); | |
174 | if(!CFEqualSafe(txn->initialViews, views) || txn->initialInCircle != isInCircle) { | |
175 | notify_post(kSOSCCViewMembershipChangedNotification); | |
176 | do_account_state_at_zero = 0; | |
177 | } | |
178 | ||
179 | if((txn->initialTrusted != (txn->account)->user_public_trusted) || (!CFEqualSafe(txn->initialKeyParameters, txn->account->user_key_parameters))){ | |
180 | notify_post(kPublicKeyNotAvailable); | |
181 | do_account_state_at_zero = 0; | |
182 | } | |
183 | ||
184 | if(do_account_state_at_zero <= 0) { | |
185 | SOSAccountLogState(txn->account); | |
186 | SOSAccountLogViewState(txn->account); | |
187 | do_account_state_at_zero = ACCOUNT_STATE_INTERVAL; | |
188 | } | |
189 | do_account_state_at_zero--; | |
190 | ||
191 | CFReleaseNull(views); | |
192 | ||
193 | } | |
194 | ||
195 | void SOSAccountTransactionFinishAndRestart(SOSAccountTransactionRef txn) { | |
196 | SOSAccountTransactionFinish(txn); | |
197 | SOSAccountTransactionRestart(txn); | |
198 | } | |
199 |