2 * Copyright (c) 2009-2010,2012-2015 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@
24 #import <Foundation/Foundation.h>
25 #import <Foundation/NSXPCConnection_Private.h>
26 #import <Security/Security.h>
28 #import <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
30 #import <dispatch/dispatch.h>
32 #import <utilities/debugging.h>
33 #import <utilities/SecCFWrappers.h>
35 #import <Security/SecureObjectSync/SOSInternal.h>
36 #import <Security/CKKSControlProtocol.h>
37 #include <Security/SecureObjectSync/SOSCloudCircle.h>
39 #include "secToolFileIO.h"
40 #include "accountCirclesViewsPrint.h"
41 #import "CKKSControlProtocol.h"
42 #import "SecItemPriv.h"
46 @interface NSString (FileOutput)
47 - (void) writeToStdOut;
48 - (void) writeToStdErr;
51 @implementation NSString (FileOutput)
53 - (void) writeToStdOut {
54 fputs([self UTF8String], stdout);
56 - (void) writeToStdErr {
57 fputs([self UTF8String], stderr);
62 @interface NSData (Hexinization)
64 - (NSString*) asHexString;
68 @implementation NSData (Hexinization)
70 - (NSString*) asHexString {
71 return (__bridge_transfer NSString*) CFDataCopyHexString((__bridge CFDataRef)self);
76 static NSString *dictionaryToString(NSDictionary *dict) {
77 NSMutableString *result = [NSMutableString stringWithCapacity:0];
78 [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
79 [result appendFormat:@"%@=%@,", key, obj];
81 return [result substringToIndex:result.length-(result.length>0)];
84 @implementation NSDictionary (OneLiner)
86 - (NSString*) asOneLineString {
87 return dictionaryToString(self);
93 circle_sysdiagnose(void)
95 SOSLogSetOutputTo(NULL,NULL);
96 SOSCCDumpCircleInformation();
100 engine_sysdiagnose(void)
102 [@"Engine state:\n" writeToStdOut];
104 CFErrorRef error = NULL;
106 if (!SOSCCForEachEngineStateAsString(&error, ^(CFStringRef oneStateString) {
107 [(__bridge NSString*) oneStateString writeToStdOut];
108 [@"\n" writeToStdOut];
110 [[NSString stringWithFormat: @"No engine state, got error: %@", error] writeToStdOut];
115 Here are the commands to dump out all keychain entries used by HomeKit:
116 security item class=genp,sync=1,agrp=com.apple.hap.pairing;
117 security item class=genp,sync=0,agrp=com.apple.hap.pairing;
118 security item class=genp,sync=0,agrp=com.apple.hap.metadata
121 static void printSecItems(NSString *subsystem, CFTypeRef result) {
123 if (CFGetTypeID(result) == CFArrayGetTypeID()) {
124 NSArray *items = (__bridge NSArray *)(result);
126 for (item in items) {
127 if ([item respondsToSelector:@selector(asOneLineString)]) {
128 [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut];
132 NSObject *item = (__bridge NSObject *)(result);
133 if ([item respondsToSelector:@selector(asOneLineString)]) {
134 [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut];
141 homekit_sysdiagnose(void)
143 NSString *kAccessGroupHapPairing = @"com.apple.hap.pairing";
144 NSString *kAccessGroupHapMetadata = @"com.apple.hap.metadata";
146 [@"HomeKit keychain state:\n" writeToStdOut];
148 // First look for syncable hap.pairing items
149 NSMutableDictionary* query = [@{
150 (id)kSecClass : (id)kSecClassGenericPassword,
151 (id)kSecAttrAccessGroup : kAccessGroupHapPairing,
152 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
153 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
154 (id)kSecReturnAttributes: @YES,
155 (id)kSecReturnData: @NO,
158 CFTypeRef result = NULL;
159 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
160 if (status == noErr) {
161 printSecItems(@"HomeKit", result);
163 CFReleaseNull(result);
165 // Now look for non-syncable hap.pairing items
166 query[(id)kSecAttrSynchronizable] = @NO;
167 status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
168 if (status == noErr) {
169 printSecItems(@"HomeKit", result);
171 CFReleaseNull(result);
173 // Finally look for non-syncable hap.metadata items
174 query[(id)kSecAttrAccessGroup] = kAccessGroupHapMetadata;
175 status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
176 if (status == noErr) {
177 printSecItems(@"HomeKit", result);
179 CFReleaseNull(result);
183 unlock_sysdiagnose(void)
185 NSString *kAccessGroupAutoUnlock = @"com.apple.continuity.unlock";
187 [@"AutoUnlock keychain state:\n" writeToStdOut];
189 NSDictionary* query = @{
190 (id)kSecClass : (id)kSecClassGenericPassword,
191 (id)kSecAttrAccessGroup : kAccessGroupAutoUnlock,
192 (id)kSecAttrAccount : @"com.apple.continuity.auto-unlock.sync",
193 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
194 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
195 (id)kSecReturnAttributes: @YES,
196 (id)kSecReturnData: @NO,
199 CFTypeRef result = NULL;
200 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
201 if (status == noErr) {
202 printSecItems(@"AutoUnlock", result);
204 CFReleaseNull(result);
207 static void idsproxy_print_message(CFDictionaryRef messages)
209 NSDictionary<NSString*, NSDictionary*> *idsMessages = (__bridge NSDictionary *)messages;
211 printf("IDS messages in flight: %d\n", (int)[idsMessages count]);
213 [idsMessages enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull identifier, NSDictionary* _Nonnull messageDictionary, BOOL * _Nonnull stop) {
214 printf("message identifier: %s\n", [identifier cStringUsingEncoding:NSUTF8StringEncoding]);
216 NSDictionary *messageDataAndPeerID = [messageDictionary valueForKey:(__bridge NSString*)kIDSMessageToSendKey];
217 [messageDataAndPeerID enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull peerID, NSData* _Nonnull messageData, BOOL * _Nonnull stop1) {
219 printf("size of message to recipient: %lu\n", (unsigned long)[messageData length]);
222 NSString *deviceID = [messageDictionary valueForKey:(__bridge NSString*)kIDSMessageRecipientDeviceID];
224 printf("recipient device id: %s\n", [deviceID cStringUsingEncoding:NSUTF8StringEncoding]);
230 idsproxy_sysdiagnose(void)
233 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
234 __block CFDictionaryRef returned = NULL;
236 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
237 SOSCloudKeychainRetrievePendingMessageFromProxy(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error) {
238 secdebug("SOSCloudKeychainRetrievePendingMessageFromProxy", "returned: %@", returnedValues);
239 CFRetainAssign(returned, returnedValues);
240 dispatch_semaphore_signal(wait_for);
243 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 2ull * NSEC_PER_SEC));
244 secdebug("idsproxy sysdiagnose", "messages: %@", returned);
246 idsproxy_print_message(returned);
250 kvs_sysdiagnose(void) {
251 SOSLogSetOutputTo(NULL,NULL);
252 SOSCCDumpCircleKVSInformation(NULL);
257 ckks_analytics_sysdiagnose(void)
259 CFErrorRef error = NULL;
260 xpc_endpoint_t xpcEndpoint = _SecSecuritydCopyCKKSEndpoint(&error);
262 [[NSString stringWithFormat:@"failed to get CKKSControl endpoint with error: %@\n", error] writeToStdErr];
266 NSXPCInterface* xpcInterface = [NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)];
267 NSXPCListenerEndpoint* listenerEndpoint = [[NSXPCListenerEndpoint alloc] init];
268 [listenerEndpoint _setEndpoint:xpcEndpoint];
270 NSXPCConnection* xpcConnection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint];
271 if (!xpcConnection) {
272 [@"failed to setup xpc connection for CKKSControl\n" writeToStdErr];
275 xpcConnection.remoteObjectInterface = xpcInterface;
276 [xpcConnection resume];
278 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
279 [[xpcConnection remoteObjectProxyWithErrorHandler:^(NSError* rpcError) {
280 [[NSString stringWithFormat:@"Error talking with daemon: %@\n", rpcError] writeToStdErr];
281 dispatch_semaphore_signal(semaphore);
282 }] rpcGetAnalyticsSysdiagnoseWithReply:^(NSString* sysdiagnose, NSError* rpcError) {
283 if (sysdiagnose && !error) {
284 [[NSString stringWithFormat:@"\nAnalytics sysdiagnose:\n\n%@\n", sysdiagnose] writeToStdOut];
287 [[NSString stringWithFormat:@"error retrieving sysdiagnose: %@\n", rpcError] writeToStdErr];
290 dispatch_semaphore_signal(semaphore);
293 if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
294 [@"\n\nError: timed out waiting for response\n" writeToStdErr];
299 main(int argc, const char ** argv)
302 printf("sysdiagnose keychain\n");
304 circle_sysdiagnose();
305 engine_sysdiagnose();
306 homekit_sysdiagnose();
307 unlock_sysdiagnose();
308 idsproxy_sysdiagnose();
309 ckks_analytics_sysdiagnose();
311 // Keep this one last