KeychainCheck.m
1 /* 2 * Copyright (c) 2017 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 25 #import "KeychainCheck.h" 26 #import "SFKeychainControl.h" 27 #import "builtin_commands.h" 28 #import "SOSControlHelper.h" 29 #import "SOSTypes.h" 30 #import "CKKSControlProtocol.h" 31 #import <Security/SecItemPriv.h> 32 #import <Foundation/NSXPCConnection_Private.h> 33 34 @interface KeychainCheck () 35 36 - (void)checkKeychain; 37 - (void)cleanKeychain; 38 39 @end 40 41 @implementation KeychainCheck { 42 NSXPCConnection* _connection; 43 } 44 45 - (instancetype)initWithEndpoint:(xpc_endpoint_t)endpoint 46 { 47 if (self = [super init]) { 48 NSXPCListenerEndpoint* listenerEndpoint = [[NSXPCListenerEndpoint alloc] init]; 49 [listenerEndpoint _setEndpoint:endpoint]; 50 _connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint]; 51 if (!_connection) { 52 return nil; 53 } 54 55 NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainControl)]; 56 _connection.remoteObjectInterface = interface; 57 [_connection resume]; 58 } 59 60 return self; 61 } 62 63 - (void)checkKeychain 64 { 65 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 66 [[_connection remoteObjectProxyWithErrorHandler:^(NSError* error) { 67 NSLog(@"failed to communicate with server with error: %@", error); 68 dispatch_semaphore_signal(semaphore); 69 }] rpcFindCorruptedItemsWithReply:^(NSArray* corruptedItems, NSError* error) { 70 if (error) { 71 NSLog(@"error searching keychain: %@", error.localizedDescription); 72 } 73 74 if (corruptedItems.count > 0) { 75 NSLog(@"found %d corrupted items", (int)corruptedItems.count); 76 } 77 else { 78 NSLog(@"no corrupted items found"); 79 } 80 81 dispatch_semaphore_signal(semaphore); 82 }]; 83 84 if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)) { 85 NSLog(@"timed out trying to communicate with server"); 86 } 87 } 88 89 - (void)cleanKeychain 90 { 91 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 92 [[_connection remoteObjectProxyWithErrorHandler:^(NSError* error) { 93 NSLog(@"failed to communicate with server with error: %@", error); 94 dispatch_semaphore_signal(semaphore); 95 }] rpcDeleteCorruptedItemsWithReply:^(bool success, NSError* error) { 96 if (success) { 97 NSLog(@"successfully cleaned keychain"); 98 } 99 else { 100 NSLog(@"error attempting to clean keychain: %@", error); 101 } 102 103 dispatch_semaphore_signal(semaphore); 104 }]; 105 106 if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)) { 107 NSLog(@"timed out trying to communicate with server"); 108 } 109 } 110 111 @end 112 113 int command_keychain_check(int argc, char* const* argv) 114 { 115 KeychainCheck* keychainCheck = [[KeychainCheck alloc] initWithEndpoint:_SecSecuritydCopyKeychainControlEndpoint(NULL)]; 116 [keychainCheck checkKeychain]; 117 return 0; 118 } 119 120 int command_keychain_cleanup(int argc, char* const* argv) 121 { 122 KeychainCheck* keychainCheck = [[KeychainCheck alloc] initWithEndpoint:_SecSecuritydCopyKeychainControlEndpoint(NULL)]; 123 [keychainCheck cleanKeychain]; 124 return 0; 125 } 126 127 int verify_backup_integrity(int argc, char * const *argv) { 128 int arg; 129 BOOL lightweight = NO; 130 131 while ((arg = getopt(argc, argv, "l")) != -1) { 132 switch(arg) { 133 case 'l': 134 lightweight = YES; 135 break; 136 } 137 } 138 139 NSLog(@"Running backup integrity validation in %@ mode", lightweight ? @"lightweight" : @"default"); 140 SecItemVerifyBackupIntegrity(lightweight, ^(NSDictionary* results, NSError *error) { 141 NSLog(@"%@", results); 142 }); 143 144 return 0; 145 }