2 * Copyright (c) 2015 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 * This is to fool os services to not provide the Keychain manager
26 * interface that doesn't work since we don't have unified headers
27 * between iOS and OS X. rdar://23405418/
29 #define __KEYCHAINCORE__ 1
31 #import <Foundation/Foundation.h>
32 #import <Foundation/NSXPCConnection_Private.h>
33 #import <Security/Security.h>
34 #import <Security/SecItemPriv.h>
35 #import <Security/SecureObjectSync/SOSTypes.h>
36 #include "keychain/SecureObjectSync/SOSControlHelper.h"
37 #import <ipc/securityd_client.h>
41 #include "builtin_commands.h"
44 @interface SOSStatus : NSObject
45 @property NSXPCConnection *connection;
47 - (void)printPerformanceCounters:(bool)asPList;
50 @implementation SOSStatus
54 if ((self = [super init]) == NULL)
57 NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(SOSControlProtocol)];
58 _SOSControlSetupInterface(interface);
60 self.connection = [[NSXPCConnection alloc] initWithMachServiceName:@(kSecuritydSOSServiceName) options:0];
61 if (self.connection == NULL){
64 self.connection.remoteObjectInterface = interface;
66 [self.connection resume];
72 - (void)printPerformanceCounters:(bool)asPList
74 dispatch_semaphore_t sema1 = dispatch_semaphore_create(0);
75 dispatch_semaphore_t sema2 = dispatch_semaphore_create(0);
76 dispatch_semaphore_t sema3 = dispatch_semaphore_create(0);
78 NSMutableDictionary<NSString *, NSNumber *> *merged = [NSMutableDictionary dictionary];
79 __block NSMutableDictionary<NSString *, NSString *> *diagnostics = [NSMutableDictionary dictionary];
81 [[self.connection remoteObjectProxy] kvsPerformanceCounters:^(NSDictionary <NSString *, NSNumber *> *counters){
82 if (counters == NULL){
83 printf("no KVS counters!");
87 [merged addEntriesFromDictionary:counters];
88 dispatch_semaphore_signal(sema1);
91 [[self.connection remoteObjectProxy] rateLimitingPerformanceCounters:^(NSDictionary <NSString *, NSString *> *returnedDiagnostics){
92 if (returnedDiagnostics == NULL){
93 printf("no rate limiting counters!");
96 diagnostics = [[NSMutableDictionary alloc]initWithDictionary:returnedDiagnostics];
97 dispatch_semaphore_signal(sema3);
99 dispatch_semaphore_wait(sema1, DISPATCH_TIME_FOREVER);
100 dispatch_semaphore_wait(sema2, DISPATCH_TIME_FOREVER);
101 dispatch_semaphore_wait(sema3, DISPATCH_TIME_FOREVER);
104 NSData *data = [NSPropertyListSerialization dataWithPropertyList:merged format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL];
106 printf("%.*s\n", (int)[data length], [data bytes]);
108 [merged enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSNumber * obj, BOOL *stop) {
109 printf("%s - %lld\n", [key UTF8String], [obj longLongValue]);
113 [diagnostics enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSString * obj, BOOL * stop) {
114 printf("%s - %s\n", [key UTF8String], [obj UTF8String]);
122 usage(const char *command, struct option *options)
124 printf("%s %s [...options]\n", getprogname(), command);
125 for (unsigned n = 0; options[n].name; n++) {
126 printf("\t [-%c|--%s\n", options[n].val, options[n].name);
132 command_sos_stats(__unused int argc, __unused char * const * argv)
135 int option_index = 0, ch;
137 SOSStatus *control = [[SOSStatus alloc] init];
139 bool asPlist = false;
140 struct option long_options[] =
142 /* These options set a flag. */
143 {"plist", no_argument, NULL, 'p'},
147 while ((ch = getopt_long(argc, argv, "p", long_options, &option_index)) != -1) {
156 usage("sos-stats", long_options);
157 return SHOW_USAGE_MESSAGE;
162 [control printPerformanceCounters:asPlist];
168 static void printControlFailureMessage(NSError *error) {
169 printf("%s", [[NSString stringWithFormat:@"Failed to send messages to soscontrol object: %@\n", error] UTF8String]);
173 command_sos_control(__unused int argc, __unused char * const * argv)
176 int option_index = 0, ch;
178 bool assertStashAccountKey = false;
179 bool triggerSync = false;
180 NSMutableArray<NSString *>* syncingPeers = NULL;
181 bool triggerBackup = false;
182 NSMutableArray<NSString*>* backupPeers = NULL;
183 SOSAccountGhostBustingOptions gboptions = 0;
185 bool gbtriggered = false;
186 bool circleHash = false;
187 bool triggerRingUpdate = false;
188 bool iCloudIdentityStatus = false;
190 static struct option long_options[] =
192 /* These options set a flag. */
193 {"assertStashAccountKey", no_argument, NULL, 'a'},
194 {"trigger-backup", optional_argument, NULL, 'B'},
195 {"trigger-ring-update", no_argument, NULL, 'R'},
196 {"trigger-sync", optional_argument, NULL, 's'},
197 {"circle-hash", optional_argument, NULL, 'H'},
198 {"ghostbustByMID", optional_argument, NULL, 'M'},
199 {"ghostbustBySerial", optional_argument, NULL, 'S'},
200 {"ghostbustiCloudIdentities", optional_argument, NULL, 'I'},
201 {"ghostbustByAge", optional_argument, NULL, 'A'},
202 {"ghostbustInfo", optional_argument, NULL, 'G'},
203 {"ghostbustTriggered", optional_argument, NULL, 'T'},
204 {"icloudIdentityStatus", optional_argument, NULL, 'i'},
208 while ((ch = getopt_long(argc, argv, "as:AB:GHIMRSTi", long_options, &option_index)) != -1) {
211 assertStashAccountKey = true;
217 if (syncingPeers == NULL) {
218 syncingPeers = [NSMutableArray array];
220 [syncingPeers addObject:[NSString stringWithUTF8String:optarg]];
225 gboptions |= SOSGhostBustSerialByAge;
229 triggerBackup = true;
231 if (backupPeers == NULL) {
232 backupPeers = [NSMutableArray array];
234 [backupPeers addObject:[NSString stringWithUTF8String:optarg]];
243 gboptions |= SOSGhostBustByMID;
247 triggerRingUpdate = true;
250 gboptions |= SOSGhostBustBySerialNumber;
254 gboptions |= SOSGhostBustiCloudIdentities;
265 iCloudIdentityStatus = true;
270 usage("sos-control", long_options);
271 return SHOW_USAGE_MESSAGE;
276 SOSStatus *control = [[SOSStatus alloc] init];
278 errx(1, "no SOS control object");
281 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
282 printControlFailureMessage(error);
283 }] ghostBustTriggerTimed:gboptions complete:^(bool ghostBusted, NSError *error) {
285 printf("ghostbusted devices\n");
287 printf("%s", [[NSString stringWithFormat:@"Failed ghostbusting: %@\n", error] UTF8String]);
289 printf("no ghosts found\n");
293 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
294 printControlFailureMessage(error);
295 }] ghostBustInfo: ^(NSData *json, NSError *error) {
296 printf("%s\n", [[[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding] UTF8String]);
298 } else if (gboptions != 0) {
299 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
300 printControlFailureMessage(error);
301 }] ghostBust:gboptions complete:^(bool ghostBusted, NSError *error) {
303 printf("ghostbusted devices\n");
305 printf("%s", [[NSString stringWithFormat:@"Failed ghostbusting: %@\n", error] UTF8String]);
307 printf("no ghosts found\n");
310 } else if (triggerSync) {
311 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
312 printControlFailureMessage(error);
313 }] rpcTriggerSync:syncingPeers complete:^(bool res, NSError *error) {
315 printf("starting to sync was successful\n");
317 printf("%s", [[NSString stringWithFormat:@"Failed to start sync: %@\n", error] UTF8String]);
320 } else if (triggerBackup) {
321 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
322 printControlFailureMessage(error);
323 }] rpcTriggerBackup:backupPeers complete:^(NSError *error) {
325 printf("trigger backup was successful\n");
327 printf("%s", [[NSString stringWithFormat:@"Failed to start backup: %@\n", error] UTF8String]);
330 } else if (triggerRingUpdate) {
331 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
332 printControlFailureMessage(error);
333 }] rpcTriggerRingUpdate:^(NSError *error) {
335 printf("trigger ring update was successful\n");
337 printf("%s", [[NSString stringWithFormat:@"Failed to start ring update: %@\n", error] UTF8String]);
341 } else if (assertStashAccountKey) {
342 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
343 printControlFailureMessage(error);
344 }] assertStashedAccountCredential:^(BOOL res, NSError *error) {
346 printf("successfully asserted stashed credential\n");
348 printf("%s", [[NSString stringWithFormat:@"failed to assert stashed credential: %@\n", error] UTF8String]);
351 } else if (circleHash) {
352 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
353 printControlFailureMessage(error);
354 }] circleHash:^(NSString *hash, NSError *error) {
356 printf("%s", [[NSString stringWithFormat:@"circle hash: %@\n", hash] UTF8String]);
358 printf("%s", [[NSString stringWithFormat:@"failed to get circle digest: %@\n", error] UTF8String]);
362 } else if (iCloudIdentityStatus) {
363 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
364 printControlFailureMessage(error);
365 }] iCloudIdentityStatus:^(NSData *json, NSError *error) {
367 printf("iCloudIdentityStatus:\n%s\n", [[[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding] UTF8String]);
369 printf("%s", [[NSString stringWithFormat:@"failed to get iCloudIdentityStatus: %@\n", error] UTF8String]);
375 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
376 printControlFailureMessage(error);
377 }] userPublicKey:^(BOOL trusted, NSData *spki, NSError *error) {
378 printf("trusted: %s\n", trusted ? "yes" : "no");
379 printf("userPublicKey: %s\n", [[spki base64EncodedStringWithOptions:0] UTF8String]);
382 [[control.connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) {
383 printControlFailureMessage(error);
384 }] stashedCredentialPublicKey:^(NSData *spki, NSError *error) {
385 NSString *pkey = [spki base64EncodedStringWithOptions:0];
387 pkey = @"not available";
388 printf("cachedCredentialPublicKey: %s\n", [pkey UTF8String]);
396 int command_watchdog(int argc, char* const * argv)
398 SOSStatus* control = [[SOSStatus alloc] init];
399 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
402 printf("getting watchdog parameters...\n");
403 [[control.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
404 printControlFailureMessage(error);
405 dispatch_semaphore_signal(semaphore);
406 }] getWatchdogParameters:^(NSDictionary* parameters, NSError* error) {
408 printf("error getting watchdog parameters: %s", error.localizedDescription.UTF8String);
411 printf("watchdog parameters:\n");
412 [parameters enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSObject* value, BOOL* stop) {
413 printf("\t%s - %s\n", key.description.UTF8String, value.description.UTF8String);
417 dispatch_semaphore_signal(semaphore);
421 printf("attempting to set watchdog parameters...\n");
422 NSString* parameter = [[NSString alloc] initWithUTF8String:argv[1]];
423 NSInteger value = [[[NSString alloc] initWithUTF8String:argv[2]] integerValue];
424 [[control.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
425 printControlFailureMessage(error);
426 dispatch_semaphore_signal(semaphore);
427 }] setWatchdogParmeters:@{parameter : @(value)} complete:^(NSError* error) {
429 printf("error attempting to set watchdog parameters: %s\n", error.localizedDescription.UTF8String);
432 printf("successfully set watchdog parameter\n");
435 dispatch_semaphore_signal(semaphore);
439 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);