2 * Copyright (c) 2017 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@
25 #import "KeychainCheck.h"
26 #import "SFKeychainControl.h"
27 #import "builtin_commands.h"
28 #import "SOSControlHelper.h"
30 #import "CKKSControlProtocol.h"
31 #import <Security/SecItemPriv.h>
32 #import <Foundation/NSXPCConnection_Private.h>
34 @interface KeychainCheck ()
36 - (void)checkKeychain;
37 - (void)cleanKeychain;
41 @implementation KeychainCheck {
42 NSXPCConnection* _connection;
45 - (instancetype)initWithEndpoint:(xpc_endpoint_t)endpoint
47 if (self = [super init]) {
48 NSXPCListenerEndpoint* listenerEndpoint = [[NSXPCListenerEndpoint alloc] init];
49 [listenerEndpoint _setEndpoint:endpoint];
50 _connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint];
55 NSXPCInterface* interface = [NSXPCInterface interfaceWithProtocol:@protocol(SFKeychainControl)];
56 _connection.remoteObjectInterface = interface;
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) {
71 NSLog(@"error searching keychain: %@", error.localizedDescription);
74 if (corruptedItems.count > 0) {
75 NSLog(@"found %d corrupted items", (int)corruptedItems.count);
78 NSLog(@"no corrupted items found");
81 dispatch_semaphore_signal(semaphore);
84 if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)) {
85 NSLog(@"timed out trying to communicate with server");
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) {
97 NSLog(@"successfully cleaned keychain");
100 NSLog(@"error attempting to clean keychain: %@", error);
103 dispatch_semaphore_signal(semaphore);
106 if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)) {
107 NSLog(@"timed out trying to communicate with server");
113 int command_keychain_check(int argc, char* const* argv)
115 KeychainCheck* keychainCheck = [[KeychainCheck alloc] initWithEndpoint:_SecSecuritydCopyKeychainControlEndpoint(NULL)];
116 [keychainCheck checkKeychain];
120 int command_keychain_cleanup(int argc, char* const* argv)
122 KeychainCheck* keychainCheck = [[KeychainCheck alloc] initWithEndpoint:_SecSecuritydCopyKeychainControlEndpoint(NULL)];
123 [keychainCheck cleanKeychain];
127 int verify_backup_integrity(int argc, char * const *argv) {
129 BOOL lightweight = NO;
131 while ((arg = getopt(argc, argv, "l")) != -1) {
139 NSLog(@"Running backup integrity validation in %@ mode", lightweight ? @"lightweight" : @"default");
140 SecItemVerifyBackupIntegrity(lightweight, ^(NSDictionary* results, NSError *error) {
141 NSLog(@"%@", results);