]> git.saurik.com Git - apple/security.git/blob - security-sysdiagnose/security-sysdiagnose.m
Security-58286.41.2.tar.gz
[apple/security.git] / security-sysdiagnose / security-sysdiagnose.m
1 /*
2 * Copyright (c) 2009-2010,2012-2015 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #import <Foundation/Foundation.h>
25 #import <Foundation/NSXPCConnection_Private.h>
26 #import <Security/Security.h>
27
28 #import <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
29
30 #import <dispatch/dispatch.h>
31
32 #import <utilities/debugging.h>
33 #import <utilities/SecCFWrappers.h>
34
35 #import <Security/SecureObjectSync/SOSInternal.h>
36 #import <Security/CKKSControlProtocol.h>
37 #include <Security/SecureObjectSync/SOSCloudCircle.h>
38
39 #include "secToolFileIO.h"
40 #include "accountCirclesViewsPrint.h"
41 #import "CKKSControlProtocol.h"
42 #import "SecItemPriv.h"
43
44 #include <stdio.h>
45
46 @interface NSString (FileOutput)
47 - (void) writeToStdOut;
48 - (void) writeToStdErr;
49 @end
50
51 @implementation NSString (FileOutput)
52
53 - (void) writeToStdOut {
54 fputs([self UTF8String], stdout);
55 }
56 - (void) writeToStdErr {
57 fputs([self UTF8String], stderr);
58 }
59
60 @end
61
62 @interface NSData (Hexinization)
63
64 - (NSString*) asHexString;
65
66 @end
67
68 @implementation NSData (Hexinization)
69
70 - (NSString*) asHexString {
71 return (__bridge_transfer NSString*) CFDataCopyHexString((__bridge CFDataRef)self);
72 }
73
74 @end
75
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];
80 }];
81 return [result substringToIndex:result.length-(result.length>0)];
82 }
83
84 @implementation NSDictionary (OneLiner)
85
86 - (NSString*) asOneLineString {
87 return dictionaryToString(self);
88 }
89
90 @end
91
92 static void
93 circle_sysdiagnose(void)
94 {
95 SOSLogSetOutputTo(NULL,NULL);
96 SOSCCDumpCircleInformation();
97 }
98
99 static void
100 engine_sysdiagnose(void)
101 {
102 [@"Engine state:\n" writeToStdOut];
103
104 CFErrorRef error = NULL;
105
106 if (!SOSCCForEachEngineStateAsString(&error, ^(CFStringRef oneStateString) {
107 [(__bridge NSString*) oneStateString writeToStdOut];
108 [@"\n" writeToStdOut];
109 })) {
110 [[NSString stringWithFormat: @"No engine state, got error: %@", error] writeToStdOut];
111 }
112 }
113
114 /*
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
119 */
120
121 static void printSecItems(NSString *subsystem, CFTypeRef result) {
122 if (result) {
123 if (CFGetTypeID(result) == CFArrayGetTypeID()) {
124 NSArray *items = (__bridge NSArray *)(result);
125 NSObject *item;
126 for (item in items) {
127 if ([item respondsToSelector:@selector(asOneLineString)]) {
128 [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut];
129 }
130 }
131 } else {
132 NSObject *item = (__bridge NSObject *)(result);
133 if ([item respondsToSelector:@selector(asOneLineString)]) {
134 [[NSString stringWithFormat: @"%@: %@\n", subsystem, [(NSMutableDictionary *)item asOneLineString]] writeToStdOut];
135 }
136 }
137 }
138 }
139
140 static void
141 homekit_sysdiagnose(void)
142 {
143 NSString *kAccessGroupHapPairing = @"com.apple.hap.pairing";
144 NSString *kAccessGroupHapMetadata = @"com.apple.hap.metadata";
145
146 [@"HomeKit keychain state:\n" writeToStdOut];
147
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,
156 } mutableCopy];
157
158 CFTypeRef result = NULL;
159 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
160 if (status == noErr) {
161 printSecItems(@"HomeKit", result);
162 }
163 CFReleaseNull(result);
164
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);
170 }
171 CFReleaseNull(result);
172
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);
178 }
179 CFReleaseNull(result);
180 }
181
182 static void
183 unlock_sysdiagnose(void)
184 {
185 NSString *kAccessGroupAutoUnlock = @"com.apple.continuity.unlock";
186
187 [@"AutoUnlock keychain state:\n" writeToStdOut];
188
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,
197 };
198
199 CFTypeRef result = NULL;
200 OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
201 if (status == noErr) {
202 printSecItems(@"AutoUnlock", result);
203 }
204 CFReleaseNull(result);
205 }
206
207 static void idsproxy_print_message(CFDictionaryRef messages)
208 {
209 NSDictionary<NSString*, NSDictionary*> *idsMessages = (__bridge NSDictionary *)messages;
210
211 printf("IDS messages in flight: %d\n", (int)[idsMessages count]);
212
213 [idsMessages enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull identifier, NSDictionary* _Nonnull messageDictionary, BOOL * _Nonnull stop) {
214 printf("message identifier: %s\n", [identifier cStringUsingEncoding:NSUTF8StringEncoding]);
215
216 NSDictionary *messageDataAndPeerID = [messageDictionary valueForKey:(__bridge NSString*)kIDSMessageToSendKey];
217 [messageDataAndPeerID enumerateKeysAndObjectsUsingBlock:^(NSString* _Nonnull peerID, NSData* _Nonnull messageData, BOOL * _Nonnull stop1) {
218 if(messageData)
219 printf("size of message to recipient: %lu\n", (unsigned long)[messageData length]);
220 }];
221
222 NSString *deviceID = [messageDictionary valueForKey:(__bridge NSString*)kIDSMessageRecipientDeviceID];
223 if(deviceID)
224 printf("recipient device id: %s\n", [deviceID cStringUsingEncoding:NSUTF8StringEncoding]);
225
226 }];
227 }
228
229 static void
230 idsproxy_sysdiagnose(void)
231 {
232
233 dispatch_semaphore_t wait_for = dispatch_semaphore_create(0);
234 __block CFDictionaryRef returned = NULL;
235
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);
241 });
242
243 dispatch_semaphore_wait(wait_for, dispatch_time(DISPATCH_TIME_NOW, 2ull * NSEC_PER_SEC));
244 secdebug("idsproxy sysdiagnose", "messages: %@", returned);
245
246 idsproxy_print_message(returned);
247 }
248
249 static void
250 kvs_sysdiagnose(void) {
251 SOSLogSetOutputTo(NULL,NULL);
252 SOSCCDumpCircleKVSInformation(NULL);
253 }
254
255
256 static void
257 ckks_analytics_sysdiagnose(void)
258 {
259 CFErrorRef error = NULL;
260 xpc_endpoint_t xpcEndpoint = _SecSecuritydCopyCKKSEndpoint(&error);
261 if (!xpcEndpoint) {
262 [[NSString stringWithFormat:@"failed to get CKKSControl endpoint with error: %@\n", error] writeToStdErr];
263 return;
264 }
265
266 NSXPCInterface* xpcInterface = [NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)];
267 NSXPCListenerEndpoint* listenerEndpoint = [[NSXPCListenerEndpoint alloc] init];
268 [listenerEndpoint _setEndpoint:xpcEndpoint];
269
270 NSXPCConnection* xpcConnection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint];
271 if (!xpcConnection) {
272 [@"failed to setup xpc connection for CKKSControl\n" writeToStdErr];
273 }
274
275 xpcConnection.remoteObjectInterface = xpcInterface;
276 [xpcConnection resume];
277
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];
285 }
286 else {
287 [[NSString stringWithFormat:@"error retrieving sysdiagnose: %@\n", rpcError] writeToStdErr];
288 }
289
290 dispatch_semaphore_signal(semaphore);
291 }];
292
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];
295 }
296 }
297
298 int
299 main(int argc, const char ** argv)
300 {
301 @autoreleasepool {
302 printf("sysdiagnose keychain\n");
303
304 circle_sysdiagnose();
305 engine_sysdiagnose();
306 homekit_sysdiagnose();
307 unlock_sysdiagnose();
308 idsproxy_sysdiagnose();
309 ckks_analytics_sysdiagnose();
310
311 // Keep this one last
312 kvs_sysdiagnose();
313 }
314 return 0;
315 }