/ SecurityTool / sharedTool / KeychainCheck.m
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  }