security-sysdiagnose.m [plain text]
/*
* Copyright (c) 2009-2010,2012-2015 Apple Inc. All Rights Reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#import <Foundation/Foundation.h>
#import <Foundation/NSXPCConnection_Private.h>
#import <Security/Security.h>
#import <SOSCircle/CKBridge/SOSCloudKeychainClient.h>
#import <dispatch/dispatch.h>
#import <utilities/debugging.h>
#import <utilities/SecCFWrappers.h>
#import <Security/SecureObjectSync/SOSInternal.h>
#import <Security/CKKSControlProtocol.h>
#include <Security/SecureObjectSync/SOSCloudCircle.h>
#include "secToolFileIO.h"
#include "accountCirclesViewsPrint.h"
#import "CKKSControlProtocol.h"
#import "SecItemPriv.h"
#import "supdProtocol.h"
#include <stdio.h>
@interface NSString (FileOutput)
- (void) writeToStdOut;
- (void) writeToStdErr;
@end
@implementation NSString (FileOutput)
- (void) writeToStdOut {
fputs([self UTF8String], stdout);
}
- (void) writeToStdErr {
fputs([self UTF8String], stderr);
}
@end
@interface NSData (Hexinization)
- (NSString*) asHexString;
@end
@implementation NSData (Hexinization)
- (NSString*) asHexString {
return (__bridge_transfer NSString*) CFDataCopyHexString((__bridge CFDataRef)self);
}
@end
static NSString *dictionaryToString(NSDictionary *dict) {
NSMutableString *result = [NSMutableString stringWithCapacity:0];
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
[result appendFormat:@" }];
return [result substringToIndex:result.length-(result.length>0)];
}
@implementation NSDictionary (OneLiner)
- (NSString*) asOneLineString {
return dictionaryToString(self);
}
@end
static void
circle_sysdiagnose(void)
{
SOSLogSetOutputTo(NULL,NULL);
SOSCCDumpCircleInformation();
}
static void
engine_sysdiagnose(void)
{
SOSCCDumpEngineInformation();
}
/*
Here are the commands to dump out all keychain entries used by HomeKit:
security item class=genp,sync=1,agrp=com.apple.hap.pairing;
security item class=genp,sync=0,agrp=com.apple.hap.pairing;
security item class=genp,sync=0,agrp=com.apple.hap.metadata
*/
static void printSecItems(NSString *subsystem, CFTypeRef result) {
if (result) {
if (CFGetTypeID(result) == CFArrayGetTypeID()) {
NSArray *items = (__bridge NSArray *)(result);
NSObject *item;
for (item in items) {
if ([item respondsToSelector:@selector(asOneLineString)]) {
[[NSString stringWithFormat: @" }
}
} else {
NSObject *item = (__bridge NSObject *)(result);
if ([item respondsToSelector:@selector(asOneLineString)]) {
[[NSString stringWithFormat: @" }
}
}
}
static void
homekit_sysdiagnose(void)
{
NSString *kAccessGroupHapPairing = @"com.apple.hap.pairing";
NSString *kAccessGroupHapMetadata = @"com.apple.hap.metadata";
[@"HomeKit keychain state:\n" writeToStdOut];
// First look for syncable hap.pairing items
NSMutableDictionary* query = [@{
(id)kSecClass : (id)kSecClassGenericPassword,
(id)kSecAttrAccessGroup : kAccessGroupHapPairing,
(id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
(id)kSecMatchLimit : (id)kSecMatchLimitAll,
(id)kSecReturnAttributes: @YES,
(id)kSecReturnData: @NO,
(id)kSecAttrNoLegacy : @YES,
} mutableCopy];
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
if (status == noErr) {
printSecItems(@"HomeKit", result);
}
CFReleaseNull(result);
// Now look for non-syncable hap.pairing items
query[(id)kSecAttrSynchronizable] = @NO;
status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
if (status == noErr) {
printSecItems(@"HomeKit", result);
}
CFReleaseNull(result);
// Finally look for non-syncable hap.metadata items
query[(id)kSecAttrAccessGroup] = kAccessGroupHapMetadata;
status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
if (status == noErr) {
printSecItems(@"HomeKit", result);
}
CFReleaseNull(result);
}
static void
unlock_sysdiagnose(void)
{
NSString *kAccessGroupAutoUnlock = @"com.apple.continuity.unlock";
[@"AutoUnlock keychain state:\n" writeToStdOut];
NSDictionary* query = @{
(id)kSecClass : (id)kSecClassGenericPassword,
(id)kSecAttrAccessGroup : kAccessGroupAutoUnlock,
(id)kSecAttrAccount : @"com.apple.continuity.auto-unlock.sync",
(id)kSecAttrSynchronizable: (id)kCFBooleanTrue,
(id)kSecMatchLimit : (id)kSecMatchLimitAll,
(id)kSecReturnAttributes: @YES,
(id)kSecReturnData: @NO,
};
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &result);
if (status == noErr) {
printSecItems(@"AutoUnlock", result);
}
CFReleaseNull(result);
}
static void
analytics_sysdiagnose(void)
{
NSXPCConnection* xpcConnection = [[NSXPCConnection alloc] initWithMachServiceName:@"com.apple.securityuploadd" options:NSXPCConnectionPrivileged];
if (!xpcConnection) {
[@"failed to setup xpc connection for securityuploadd\n" writeToStdErr];
return;
}
xpcConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(supdProtocol)];
[xpcConnection resume];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[[xpcConnection remoteObjectProxyWithErrorHandler:^(NSError* rpcError) {
[[NSString stringWithFormat:@"Error talking with daemon: dispatch_semaphore_signal(semaphore);
}] getSysdiagnoseDumpWithReply:^(NSString* sysdiagnose) {
if (sysdiagnose) {
[[NSString stringWithFormat:@"\nAnalytics sysdiagnose:\n\n }
dispatch_semaphore_signal(semaphore);
}];
if (dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
[@"\n\nError: timed out waiting for response\n" writeToStdErr];
}
}
static void
kvs_sysdiagnose(void) {
SOSLogSetOutputTo(NULL,NULL);
SOSCCDumpCircleKVSInformation(NULL);
}
int
main(int argc, const char ** argv)
{
@autoreleasepool {
printf("sysdiagnose keychain\n");
circle_sysdiagnose();
engine_sysdiagnose();
homekit_sysdiagnose();
unlock_sysdiagnose();
analytics_sysdiagnose();
// Keep this one last
kvs_sysdiagnose();
}
return 0;
}