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"
43 #import "supdProtocol.h"
47 @interface NSString (FileOutput)
48 - (void) writeToStdOut;
49 - (void) writeToStdErr;
52 @implementation NSString (FileOutput)
54 - (void) writeToStdOut {
55 fputs([self UTF8String], stdout);
57 - (void) writeToStdErr {
58 fputs([self UTF8String], stderr);
63 @interface NSData (Hexinization)
65 - (NSString*) asHexString;
69 @implementation NSData (Hexinization)
71 - (NSString*) asHexString {
72 return (__bridge_transfer NSString*) CFDataCopyHexString((__bridge CFDataRef)self);
77 static NSString *dictionaryToString(NSDictionary *dict) {
78 NSMutableString *result = [NSMutableString stringWithCapacity:0];
79 [dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
80 [result appendFormat:@"%@=%@,", key, obj];
82 return [result substringToIndex:result.length-(result.length>0)];
85 @implementation NSDictionary (OneLiner)
87 - (NSString*) asOneLineString {
88 return dictionaryToString(self);
94 circle_sysdiagnose(void)
96 SOSLogSetOutputTo(NULL,NULL);
97 SOSCCDumpCircleInformation();
101 engine_sysdiagnose(void)
103 SOSCCDumpEngineInformation();
107 Here are the commands to dump out all keychain entries used by HomeKit:
108 security item class=genp,sync=1,agrp=com.apple.hap.pairing;
109 security item class=genp,sync=0,agrp=com.apple.hap.pairing;
110 security item class=genp,sync=0,agrp=com.apple.hap.metadata
113 static void printSecItems(NSString *subsystem, CFTypeRef result) {
115 if (CFGetTypeID(result) == CFArrayGetTypeID()) {
116 NSArray *items = (__bridge NSArray *)(result);
118 for (item in items) {
119 if ([item respondsToSelector:@selector(asOneLineString)]) {
120 [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut];
124 NSObject *item = (__bridge NSObject *)(result);
125 if ([item respondsToSelector:@selector(asOneLineString)]) {
126 [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut];
133 homekit_sysdiagnose(void)
135 NSString *kAccessGroupHapPairing = @"com.apple.hap.pairing";
136 NSString *kAccessGroupHapMetadata = @"com.apple.hap.metadata";
138 [@"HomeKit keychain state:\n" writeToStdOut];
140 // First look for syncable hap.pairing items
141 NSMutableDictionary* query = [@{
142 (id)kSecClass : (id)kSecClassGenericPassword,
143 (id)kSecAttrAccessGroup : kAccessGroupHapPairing,
144 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
145 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
146 (id)kSecReturnAttributes: @YES,
147 (id)kSecReturnData: @NO,
150 CFTypeRef result = NULL;
151 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
152 if (status == noErr) {
153 printSecItems(@"HomeKit", result);
155 CFReleaseNull(result);
157 // Now look for non-syncable hap.pairing items
158 query[(id)kSecAttrSynchronizable] = @NO;
159 status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
160 if (status == noErr) {
161 printSecItems(@"HomeKit", result);
163 CFReleaseNull(result);
165 // Finally look for non-syncable hap.metadata items
166 query[(id)kSecAttrAccessGroup] = kAccessGroupHapMetadata;
167 status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
168 if (status == noErr) {
169 printSecItems(@"HomeKit", result);
171 CFReleaseNull(result);
175 unlock_sysdiagnose(void)
177 NSString *kAccessGroupAutoUnlock = @"com.apple.continuity.unlock";
179 [@"AutoUnlock keychain state:\n" writeToStdOut];
181 NSDictionary* query = @{
182 (id)kSecClass : (id)kSecClassGenericPassword,
183 (id)kSecAttrAccessGroup : kAccessGroupAutoUnlock,
184 (id)kSecAttrAccount : @"com.apple.continuity.auto-unlock.sync",
185 (id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
186 (id)kSecMatchLimit : (id)kSecMatchLimitAll,
187 (id)kSecReturnAttributes: @YES,
188 (id)kSecReturnData: @NO,
191 CFTypeRef result = NULL;
192 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
193 if (status == noErr) {
194 printSecItems(@"AutoUnlock", result);
196 CFReleaseNull(result);
199 static void idsproxy_print_message(CFDictionaryRef messages)
201 NSDictionary<NSString*, NSDictionary*> *idsMessages = (__bridge NSDictionary *)messages;
203 printf("IDS messages in flight: %d\n", (int)[idsMessages count]);
205 [idsMessages enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull identifier, NSDictionary* _Nonnull messageDictionary, BOOL * _Nonnull stop) {
206 printf("message identifier: %s\n", [identifier cStringUsingEncoding:NSUTF8StringEncoding]);
208 NSDictionary *messageDataAndPeerID = [messageDictionary valueForKey:(__bridge NSString*)kIDSMessageToSendKey];
209 [messageDataAndPeerID enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull peerID, NSData* _Nonnull messageData, BOOL * _Nonnull stop1) {
211 printf("size of message to recipient: %lu\n", (unsigned long)[messageData length]);
214 NSString *deviceID = [messageDictionary valueForKey:(__bridge NSString*)kIDSMessageRecipientDeviceID];
216 printf("recipient device id: %s\n", [deviceID cStringUsingEncoding:NSUTF8StringEncoding]);
222 idsproxy_sysdiagnose(void)
225 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
226 __block CFDictionaryRef returned = NULL;
228 dispatch_queue_t processQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
229 SOSCloudKeychainRetrievePendingMessageFromProxy(processQueue, ^(CFDictionaryRef returnedValues, CFErrorRef error) {
230 secdebug("SOSCloudKeychainRetrievePendingMessageFromProxy", "returned: %@", returnedValues);
231 CFRetainAssign(returned, returnedValues);
232 dispatch_semaphore_signal(wait_for);
235 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 2ull * NSEC_PER_SEC));
236 secdebug("idsproxy sysdiagnose", "messages: %@", returned);
238 idsproxy_print_message(returned);
242 analytics_sysdiagnose(void)
244 NSXPCConnection* xpcConnection = [[NSXPCConnection alloc] initWithMachServiceName:@"com.apple.securityuploadd" options:NSXPCConnectionPrivileged];
245 if (!xpcConnection) {
246 [@"failed to setup xpc connection for securityuploadd\n" writeToStdErr];
249 xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(supdProtocol)];
250 [xpcConnection resume];
252 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
253 [[xpcConnection remoteObjectProxyWithErrorHandler:^(NSError* rpcError) {
254 [[NSString stringWithFormat:@"Error talking with daemon: %@\n", rpcError] writeToStdErr];
255 dispatch_semaphore_signal(semaphore);
256 }] getSysdiagnoseDumpWithReply:^(NSString* sysdiagnose) {
258 [[NSString stringWithFormat:@"\nAnalytics sysdiagnose:\n\n%@\n", sysdiagnose] writeToStdOut];
260 dispatch_semaphore_signal(semaphore);
263 if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
264 [@"\n\nError: timed out waiting for response\n" writeToStdErr];
269 kvs_sysdiagnose(void) {
270 SOSLogSetOutputTo(NULL,NULL);
271 SOSCCDumpCircleKVSInformation(NULL);
275 main(int argc, const char ** argv)
278 printf("sysdiagnose keychain\n");
280 circle_sysdiagnose();
281 engine_sysdiagnose();
282 homekit_sysdiagnose();
283 unlock_sysdiagnose();
284 idsproxy_sysdiagnose();
285 analytics_sysdiagnose();
287 // Keep this one last