]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTUpdateTPHOperation.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / ot / OTUpdateTPHOperation.m
1
2 #if OCTAGON
3
4 #import "keychain/TrustedPeersHelper/TrustedPeersHelperProtocol.h"
5 #import "keychain/ot/categories/OTAccountMetadataClassC+KeychainSupport.h"
6
7 #import <CloudKit/CloudKit_Private.h>
8
9 #import "keychain/ckks/CloudKitCategories.h"
10
11 #import "keychain/ot/ObjCImprovements.h"
12
13 #import "keychain/ot/OTCuttlefishAccountStateHolder.h"
14 #import "keychain/ot/OTOperationDependencies.h"
15 #import "keychain/ot/OTStates.h"
16 #import "keychain/ot/OTUpdateTPHOperation.h"
17
18 @interface OTUpdateTPHOperation ()
19 @property OTOperationDependencies* deps;
20
21 @property NSOperation* finishedOp;
22
23 @property (nullable) OctagonFlag* retryFlag;
24 @end
25
26 @implementation OTUpdateTPHOperation
27 @synthesize nextState = _nextState;
28 @synthesize intendedState = _intendedState;
29
30 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
31 intendedState:(OctagonState*)intendedState
32 errorState:(OctagonState*)errorState
33 retryFlag:(OctagonFlag* _Nullable)retryFlag
34 {
35 if((self = [super init])) {
36 _deps = dependencies;
37
38 _intendedState = intendedState;
39 _nextState = errorState;
40
41 _retryFlag = retryFlag;
42 }
43 return self;
44 }
45
46 - (void)groupStart
47 {
48 WEAKIFY(self);
49 self.finishedOp = [NSBlockOperation blockOperationWithBlock:^{
50 // If we errored in some unknown way, ask to try again!
51 STRONGIFY(self);
52
53 if(self.error) {
54 if(self.retryFlag == nil) {
55 secerror("octagon: Received an error updating TPH, but no retry flag present.");
56 return;
57 }
58
59 // Is this a very scary error?
60 bool fatal = true;
61
62 OctagonPendingFlag* pendingFlag = nil;
63
64 if([self.deps.lockStateTracker isLockedError:self.error]) {
65 secnotice("octagon", "Updating trust state failed because locked, retry once unlocked: %@", self.error);
66 self.nextState = OctagonStateWaitForUnlock;
67 pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
68 conditions:OctagonPendingConditionsDeviceUnlocked];
69 fatal = false;
70 } else if ([self.error isCuttlefishError:CuttlefishErrorTransactionalFailure]) {
71 secnotice("octagon", "Transaction failure in cuttlefishm, retrying: %@", self.error);
72 fatal = false;
73 } else {
74 // more CloudKit errors should trigger a retry here
75 secnotice("octagon", "Error is currently unknown, aborting: %@", self.error);
76 }
77
78 if(!fatal) {
79 if(!pendingFlag) {
80 NSTimeInterval baseDelay = SecCKKSTestsEnabled() ? 2 : 30;
81 NSTimeInterval delay = CKRetryAfterSecondsForError(self.error) ?: baseDelay;
82 pendingFlag = [[OctagonPendingFlag alloc] initWithFlag:self.retryFlag
83 delayInSeconds:delay];
84 }
85 secnotice("octagon", "Updating trust state no fatal: requesting retry: %@",
86 pendingFlag);
87 [self.deps.flagHandler handlePendingFlag:pendingFlag];
88 }
89 }
90 }];
91 [self dependOnBeforeGroupFinished:self.finishedOp];
92
93
94 [[self.deps.cuttlefishXPC remoteObjectProxyWithErrorHandler:^(NSError * _Nonnull error) {
95 STRONGIFY(self);
96 secerror("octagon: Can't talk with TrustedPeersHelper, update is lost: %@", error);
97 self.error = error;
98 [self runBeforeGroupFinished:self.finishedOp];
99
100 }] updateWithContainer:self.deps.containerName
101 context:self.deps.contextID
102 deviceName:nil
103 serialNumber:nil
104 osVersion:nil
105 policyVersion:nil
106 policySecrets:nil
107 reply:^(TrustedPeersHelperPeerState* peerState, NSError* error) {
108 STRONGIFY(self);
109 if(error || !peerState) {
110 secerror("octagon: update errored: %@", error);
111 self.error = error;
112
113 // On an error, for now, go back to the intended state
114 // <rdar://problem/50190005> Octagon: handle lock state errors in update()
115 self.nextState = self.intendedState;
116 [self runBeforeGroupFinished:self.finishedOp];
117 return;
118 }
119
120 secnotice("octagon", "update complete: %@", peerState);
121
122 if(peerState.identityIsPreapproved) {
123 secnotice("octagon-sos", "Self peer is now preapproved!");
124 [self.deps.flagHandler handleFlag:OctagonFlagEgoPeerPreapproved];
125 }
126 if (peerState.memberChanges) {
127 secnotice("octagon", "Member list changed");
128 [self.deps.octagonAdapter sendTrustedPeerSetChangedUpdate];
129 }
130
131 if (peerState.unknownMachineIDsPresent) {
132 secnotice("octagon-authkit", "Unknown machine IDs are present; requesting fetch");
133 [self.deps.flagHandler handleFlag:OctagonFlagFetchAuthKitMachineIDList];
134 }
135
136 if(peerState.peerStatus & TPPeerStatusExcluded) {
137 secnotice("octagon", "Self peer (%@) is excluded; moving to untrusted", peerState.peerID);
138 self.nextState = OctagonStateBecomeUntrusted;
139
140 } else if(peerState.peerStatus & TPPeerStatusUnknown) {
141 secnotice("octagon", "Self peer (%@) is unknown; moving to untrusted", peerState.peerID);
142 self.nextState = OctagonStateBecomeUntrusted;
143
144 } else {
145 self.nextState = self.intendedState;
146 }
147
148 [self runBeforeGroupFinished:self.finishedOp];
149 }];
150 }
151
152 @end
153
154 #endif // OCTAGON