2 * Copyright (c) 2019 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 #import "utilities/debugging.h"
28 #import "keychain/ot/ObjCImprovements.h"
29 #import "keychain/ot/OTDetermineCDPBitStatusOperation.h"
30 #import "keychain/ot/OTStates.h"
32 @interface OTDetermineCDPBitStatusOperation ()
33 @property OTOperationDependencies* deps;
36 @implementation OTDetermineCDPBitStatusOperation
37 @synthesize intendedState = _intendedState;
38 @synthesize nextState = _nextState;
40 - (instancetype)initWithDependencies:(OTOperationDependencies*)dependencies
41 intendedState:(OctagonState*)intendedState
42 errorState:(OctagonState*)errorState
44 if((self = [super init])) {
46 _intendedState = intendedState;
47 _nextState = errorState;
54 secnotice("octagon-cdp-status", "Checking CDP status");
56 NSError* localError = nil;
57 OTAccountMetadataClassC* account = [self.deps.stateHolder loadOrCreateAccountMetadata:&localError];
58 if(localError && [self.deps.lockStateTracker isLockedError:localError]) {
59 secnotice("octagon-cdp-status", "Device is locked! restarting on unlock");
60 self.nextState = OctagonStateWaitForClassCUnlock;
65 secnotice("octagon-cdp-status", "Failed to load account metadata: %@", localError);
66 self.error = localError;
70 secnotice("octagon-cdp-status", "CDP is %@", OTAccountMetadataClassC_CDPStateAsString(account.cdpState));
72 if(account.cdpState == OTAccountMetadataClassC_CDPState_ENABLED) {
73 self.nextState = self.intendedState;
75 // If the CDP status is unknown or disabled, double-check with TPH.
76 // If there are any peers, the CDP status really should be ENABLED.
77 __block OTAccountMetadataClassC_CDPState newState = OTAccountMetadataClassC_CDPState_UNKNOWN;
80 [self.deps.cuttlefishXPCWrapper trustStatusWithContainer:self.deps.containerName
81 context:self.deps.contextID
82 reply:^(TrustedPeersHelperEgoPeerStatus *egoStatus,
86 secnotice("octagon-cdp-status", "Unable to talk with TPH; leaving CDP status as 'unknown': %@", xpcError);
90 secnotice("octagon-cdp-status", "Octagon reports %d peers", (int)egoStatus.numberOfPeersInOctagon);
91 if(egoStatus.numberOfPeersInOctagon > 0) {
92 newState = OTAccountMetadataClassC_CDPState_ENABLED;
94 // As a last gasp, check in with SOS (if enabled). If there's a circle (in or out), CDP is on
95 if(self.deps.sosAdapter.sosEnabled) {
96 secnotice("octagon-cdp-status", "Requesting SOS status...");
98 NSError* circleError = nil;
99 SOSCCStatus circleStatus = [self.deps.sosAdapter circleStatus:&circleError];
101 if(circleError || circleStatus == kSOSCCError) {
102 secnotice("octagon-cdp-status", "Error fetching circle status. Leaving CDP status as 'unknown': %@", circleError);
103 } else if(circleStatus == kSOSCCCircleAbsent) {
104 secnotice("octagon-cdp-status", "SOS reports circle absent. Setting CDP to 'disabled'");
105 newState = OTAccountMetadataClassC_CDPState_DISABLED;
107 secnotice("octagon-cdp-status", "SOS reports some existing circle (%d). Setting CDP to 'enabled'", (int)circleStatus);
108 newState = OTAccountMetadataClassC_CDPState_ENABLED;
112 secnotice("octagon-cdp-status", "No SOS. CDP bit is off.");
113 newState = OTAccountMetadataClassC_CDPState_DISABLED;
118 if(account.cdpState != newState) {
119 NSError* stateError = nil;
120 [self.deps.stateHolder persistAccountChanges:^OTAccountMetadataClassC * _Nonnull(OTAccountMetadataClassC * _Nonnull metadata) {
121 if(metadata.cdpState == OTAccountMetadataClassC_CDPState_ENABLED) {
122 secnotice("octagon-cdp-status", "CDP bit is enabled on-disk, not modifying (would have been %@)", OTAccountMetadataClassC_CDPStateAsString(newState));
124 // Set this here to perform the right state choice later
125 newState = OTAccountMetadataClassC_CDPState_ENABLED;
128 secnotice("octagon-cdp-status", "Writing CDP bit as %@", OTAccountMetadataClassC_CDPStateAsString(newState));
129 metadata.cdpState = newState;
132 } error:&stateError];
135 secnotice("octagon-cdp-status", "Failed to load account metadata: %@", stateError);
139 if(newState == OTAccountMetadataClassC_CDPState_ENABLED) {
140 self.nextState = self.intendedState;
142 self.nextState = OctagonStateWaitForCDP;