]> git.saurik.com Git - apple/security.git/blob - keychain/ckksctl/ckksctl.m
Security-58286.20.16.tar.gz
[apple/security.git] / keychain / ckksctl / ckksctl.m
1 //
2 // Security
3 //
4
5 #import <Foundation/Foundation.h>
6 #import <Foundation/NSXPCConnection_Private.h>
7 #import <Security/Security.h>
8 #import <Security/SecItemPriv.h>
9 #import <xpc/xpc.h>
10 #import <err.h>
11
12 #import "keychain/ckks/CKKS.h"
13 #import "keychain/ckks/CKKSControlProtocol.h"
14 #import "ckksctl.h"
15
16 #include "lib/SecArgParse.h"
17
18 static void nsprintf(NSString *fmt, ...) NS_FORMAT_FUNCTION(1, 2);
19 static void print_result(NSDictionary *dict, bool json_flag);
20 static void print_dict(NSDictionary *dict, int ind);
21 static void print_array(NSArray *array, int ind);
22 static void print_entry(id k, id v, int ind);
23
24 static void nsprintf(NSString *fmt, ...)
25 {
26 va_list ap;
27 va_start(ap, fmt);
28 NSString *str = [[NSString alloc] initWithFormat:fmt arguments:ap];
29 va_end(ap);
30
31 puts([str UTF8String]);
32 #if !__has_feature(objc_arc)
33 [str release];
34 #endif
35 }
36
37 static void print_result(NSDictionary *dict, bool json_flag)
38 {
39 if (json_flag) {
40 NSError *err;
41 NSData *json = [NSJSONSerialization dataWithJSONObject:dict
42 options:(NSJSONWritingPrettyPrinted | NSJSONWritingSortedKeys)
43 error:&err];
44 if (!json) {
45 NSLog(@"error: %@", err.localizedDescription);
46 } else {
47 printf("%s", [[[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding] UTF8String]);
48 }
49 } else {
50 print_dict(dict, 0);
51 }
52 }
53
54 static void print_dict(NSDictionary *dict, int ind)
55 {
56 NSArray *sortedKeys = [[dict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
57 for (id k in sortedKeys) {
58 id v = dict[k];
59 print_entry(k, v, ind);
60 }
61 }
62
63 static void print_array(NSArray *array, int ind)
64 {
65 [array enumerateObjectsUsingBlock:^(id v, NSUInteger i, BOOL *stop __unused) {
66 print_entry(@(i), v, ind);
67 }];
68 }
69
70 static void print_entry(id k, id v, int ind)
71 {
72 if ([v isKindOfClass:[NSDictionary class]]) {
73 if (ind == 0) {
74 nsprintf(@"\n%*s%@ -", ind * 4, "", k);
75 nsprintf(@"%*s========================", ind * 4, "");
76 } else if (ind == 1) {
77 nsprintf(@"\n%*s%@ -", ind * 4, "", k);
78 nsprintf(@"%*s------------------------", ind * 4, "");
79 } else {
80 nsprintf(@"%*s%@ -", ind * 4, "", k);
81 }
82
83 print_dict(v, ind + 1);
84 } else if ([v isKindOfClass:[NSArray class]]) {
85 nsprintf(@"%*s%@ -", ind * 4, "", k);
86 print_array(v, ind + 1);
87 } else {
88 nsprintf(@"%*s%@: %@", ind * 4, "", k, v);
89 }
90 }
91
92 @interface CKKSControl ()
93 @property NSXPCConnection *connection;
94 @end
95
96 @implementation CKKSControl
97
98 - (instancetype) initWithEndpoint:(xpc_endpoint_t)endpoint
99 {
100 if ((self = [super init]) == NULL)
101 return NULL;
102
103 NSXPCInterface *interface = CKKSSetupControlProtocol([NSXPCInterface interfaceWithProtocol:@protocol(CKKSControlProtocol)]);
104 NSXPCListenerEndpoint *listenerEndpoint = [[NSXPCListenerEndpoint alloc] init];
105
106 [listenerEndpoint _setEndpoint:endpoint];
107
108 self.connection = [[NSXPCConnection alloc] initWithListenerEndpoint:listenerEndpoint];
109 if (self.connection == NULL)
110 return NULL;
111
112 self.connection.remoteObjectInterface = interface;
113
114 [self.connection resume];
115
116
117 return self;
118 }
119
120 - (NSDictionary<NSString *, id> *)printPerformanceCounters
121 {
122 NSMutableDictionary *perfDict = [[NSMutableDictionary alloc] init];
123 #if OCTAGON
124 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
125
126 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
127 perfDict[@"error"] = [error description];
128 dispatch_semaphore_signal(sema);
129
130 }] performanceCounters:^(NSDictionary <NSString *, NSNumber *> *counters){
131 [counters enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSNumber * obj, BOOL *stop) {
132 perfDict[key] = obj;
133 }];
134 dispatch_semaphore_signal(sema);
135 }];
136
137 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
138 perfDict[@"error"] = @"timed out waiting for response";
139 }
140 #endif
141
142 return perfDict;
143 }
144
145 - (void)resetLocal: (NSString*)view {
146 #if OCTAGON
147 printf("Beginning local reset for %s...\n", view ? [[view description] UTF8String] : "all zones");
148 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
149
150 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
151 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
152 dispatch_semaphore_signal(sema);
153
154 }] rpcResetLocal:view reply:^(NSError* result){
155 if(result == NULL) {
156 printf("reset complete.\n");
157 } else {
158 printf("reset error: %s\n", [[result description] UTF8String]);
159 }
160 dispatch_semaphore_signal(sema);
161 }];
162
163 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
164 printf("\n\nError: timed out waiting for response\n");
165 }
166 #endif // OCTAGON
167 }
168
169 - (void)resetCloudKit: (NSString*)view {
170 #if OCTAGON
171 printf("Beginning CloudKit reset for %s...\n", view ? [[view description] UTF8String] : "all zones");
172 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
173
174 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
175 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
176 dispatch_semaphore_signal(sema);
177
178 }] rpcResetCloudKit:view reply:^(NSError* result){
179 if(result == NULL) {
180 printf("CloudKit Reset complete.\n");
181 } else {
182 printf("Reset error: %s\n", [[result description] UTF8String]);
183 }
184 dispatch_semaphore_signal(sema);
185 }];
186
187 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
188 printf("\n\nError: timed out waiting for response\n");
189 }
190 #endif // OCTAON
191 }
192
193 - (void)resync: (NSString*)view {
194 #if OCTAGON
195 printf("Beginning resync for %s...\n", view ? [[view description] UTF8String] : "all zones");
196 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
197
198 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
199 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
200 dispatch_semaphore_signal(sema);
201
202 }] rpcResync:view reply:^(NSError* result){
203 if(result == NULL) {
204 printf("resync success.\n");
205 } else {
206 printf("resync errored: %s\n", [[result description] UTF8String]);
207 }
208 dispatch_semaphore_signal(sema);
209 }];
210
211 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
212 printf("\n\nError: timed out waiting for response\n");
213 }
214 #endif // OCTAGON
215 }
216
217 - (void)getAnalyticsSysdiagnose
218 {
219 printf("Getting analytics sysdiagnose....\n");
220 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
221
222 [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
223 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
224 dispatch_semaphore_signal(sema);
225 }] rpcGetAnalyticsSysdiagnoseWithReply:^(NSString* sysdiagnose, NSError* error) {
226 if (sysdiagnose && !error) {
227 nsprintf(@"Analytics sysdiagnose:\n\n%@", sysdiagnose);
228 }
229 else {
230 nsprintf(@"error retrieving sysdiagnose: %@", error);
231 }
232
233 dispatch_semaphore_signal(sema);
234 }];
235
236 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
237 printf("\n\nError: timed out waiting for response\n");
238 }
239 }
240
241 - (void)getAnalyticsJSON
242 {
243 printf("Getting analytics json....\n");
244 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
245
246 [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
247 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
248 dispatch_semaphore_signal(sema);
249 }] rpcGetAnalyticsJSONWithReply:^(NSData* json, NSError* error) {
250 if (json && !error) {
251 nsprintf(@"Analytics JSON:\n\n%@", [[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding]);
252 }
253 else {
254 nsprintf(@"error retrieving JSON: %@", error);
255 }
256
257 dispatch_semaphore_signal(sema);
258 }];
259
260 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
261 printf("\n\nError: timed out waiting for response\n");
262 }
263 }
264
265 - (void)forceAnalyticsUpload
266 {
267 printf("Uploading....\n");
268 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
269
270 [[self.connection remoteObjectProxyWithErrorHandler:^(NSError* error) {
271 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
272 dispatch_semaphore_signal(sema);
273 }] rpcForceUploadAnalyticsWithReply:^(BOOL success, NSError* error) {
274 if (success) {
275 nsprintf(@"successfully uploaded analytics data");
276 }
277 else {
278 nsprintf(@"error uploading analytics: %@", error);
279 }
280
281 dispatch_semaphore_signal(sema);
282 }];
283
284 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 60)) != 0) {
285 printf("\n\nError: timed out waiting for response\n");
286 }
287 }
288
289 - (NSDictionary<NSString *, id> *)status: (NSString*) view {
290 NSMutableDictionary *status = [[NSMutableDictionary alloc] init];
291 #if OCTAGON
292 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
293
294 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
295 status[@"error"] = [error description];
296 dispatch_semaphore_signal(sema);
297
298 }] rpcStatus: view reply: ^(NSArray<NSDictionary*>* result, NSError* error) {
299 if(error) {
300 status[@"error"] = [error description];
301 }
302
303 if(result.count == 0u) {
304 printf("No CKKS views are active.\n");
305 }
306
307
308 for(NSDictionary* viewStatus in result) {
309 status[viewStatus[@"view"]] = viewStatus;
310 }
311 dispatch_semaphore_signal(sema);
312 }];
313
314 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5)) != 0) {
315 status[@"error"] = @"timed out";
316 }
317 #endif // OCTAGON
318 return status;
319 }
320
321 - (void)status_custom: (NSString*) view {
322 #if OCTAGON
323 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
324
325 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
326 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
327 dispatch_semaphore_signal(sema);
328
329 }] rpcStatus: view reply: ^(NSArray<NSDictionary*>* result, NSError* error) {
330 if(error) {
331 printf("ERROR FETCHING STATUS: %s\n", [[error description] UTF8String]);
332 }
333
334 if(result.count == 0u) {
335 printf("No CKKS views are active.\n");
336 }
337
338 for(NSDictionary* viewStatus in result) {
339 NSMutableDictionary* status = [viewStatus mutableCopy];
340
341 #define pop(d, key) ({ id x = d[key]; d[key] = nil; x; })
342
343 NSString* viewName = pop(status,@"view");
344 NSString* accountStatus = pop(status,@"ckaccountstatus");
345 NSString* lockStateTracker = pop(status,@"lockstatetracker");
346 NSString* accountTracker = pop(status,@"accounttracker");
347 NSString* fetcher = pop(status,@"fetcher");
348 NSString* setup = pop(status,@"setup");
349 NSString* zoneCreated = pop(status,@"zoneCreated");
350 NSString* zoneCreatedError = pop(status,@"zoneCreatedError");
351 NSString* zoneSubscribed = pop(status,@"zoneSubscribed");
352 NSString* zoneSubscribedError = pop(status,@"zoneSubscribedError");
353 NSString* zoneInitializeScheduler = pop(status,@"zoneInitializeScheduler");
354 NSString* keystate = pop(status,@"keystate");
355 NSString* keyStateError = pop(status,@"keyStateError");
356 NSString* statusError = pop(status,@"statusError");
357 NSString* currentTLK = pop(status,@"currentTLK");
358 NSString* currentClassA = pop(status,@"currentClassA");
359 NSString* currentClassC = pop(status,@"currentClassC");
360 NSString* currentManifestGeneration = pop(status,@"currentManifestGen");
361
362 NSDictionary* oqe = pop(status,@"oqe");
363 NSDictionary* iqe = pop(status,@"iqe");
364 NSDictionary* keys = pop(status,@"keys");
365 NSDictionary* ckmirror = pop(status,@"ckmirror");
366 NSArray* devicestates = pop(status, @"devicestates");
367
368 NSString* zoneSetupOperation = pop(status,@"zoneSetupOperation");
369 NSString* viewSetupOperation = pop(status,@"viewSetupOperation");
370 NSString* keyStateOperation = pop(status,@"keyStateOperation");
371 NSString* lastIncomingQueueOperation = pop(status,@"lastIncomingQueueOperation");
372 NSString* lastNewTLKOperation = pop(status,@"lastNewTLKOperation");
373 NSString* lastOutgoingQueueOperation = pop(status,@"lastOutgoingQueueOperation");
374 NSString* lastRecordZoneChangesOperation = pop(status,@"lastRecordZoneChangesOperation");
375 NSString* lastProcessReceivedKeysOperation = pop(status,@"lastProcessReceivedKeysOperation");
376 NSString* lastReencryptOutgoingItemsOperation = pop(status,@"lastReencryptOutgoingItemsOperation");
377 NSString* lastScanLocalItemsOperation = pop(status,@"lastScanLocalItemsOperation");
378
379 printf("================================================================================\n\n");
380
381 printf("View: %s\n\n", [viewName UTF8String]);
382
383 if(![statusError isEqual: [NSNull null]]) {
384 printf("ERROR FETCHING STATUS: %s\n\n", [statusError UTF8String]);
385 }
386
387 printf("CloudKit account: %s\n", [accountStatus UTF8String]);
388 printf("Account tracker: %s\n", [accountTracker UTF8String]);
389 printf("Ran setup operation: %s\n", [setup UTF8String]);
390
391 if(!([zoneCreated isEqualToString:@"yes"] && [zoneSubscribed isEqualToString:@"yes"])) {
392 printf("CK Zone Created: %s\n", [[zoneCreated description] UTF8String]);
393 printf("CK Zone Created error: %s\n", [[zoneCreatedError description] UTF8String]);
394
395 printf("CK Zone Subscribed: %s\n", [[zoneSubscribed description] UTF8String]);
396 printf("CK Zone Subscription error: %s\n", [[zoneSubscribedError description] UTF8String]);
397 printf("CK Zone initialize retry: %s\n", [[zoneInitializeScheduler description] UTF8String]);
398 printf("\n");
399 }
400
401 printf("Key state: %s\n", [keystate UTF8String]);
402 if(![keyStateError isEqual: [NSNull null]]) {
403 printf("Key State Error: %s\n", [keyStateError UTF8String]);
404 }
405 printf("Lock state: %s\n", [lockStateTracker UTF8String]);
406
407 printf("Current TLK: %s\n", [currentTLK isEqual: [NSNull null]] ? "null" : [currentTLK UTF8String]);
408 printf("Current ClassA: %s\n", [currentClassA isEqual: [NSNull null]] ? "null" : [currentClassA UTF8String]);
409 printf("Current ClassC: %s\n", [currentClassC isEqual: [NSNull null]] ? "null" : [currentClassC UTF8String]);
410
411 printf("Outgoing Queue counts: %s\n", [[oqe description] UTF8String]);
412 printf("Incoming Queue counts: %s\n", [[iqe description] UTF8String]);
413 printf("Key counts: %s\n", [[keys description] UTF8String]);
414 printf("latest manifest generation: %s\n", [currentManifestGeneration isEqual:[NSNull null]] ? "null" : currentManifestGeneration.UTF8String);
415
416 printf("Item counts (by key): %s\n", [[ckmirror description] UTF8String]);
417 printf("Peer states: %s\n", [[devicestates description] UTF8String]);
418
419 printf("zone change fetcher: %s\n", [[fetcher description] UTF8String]);
420 printf("zoneSetupOperation: %s\n", [zoneSetupOperation isEqual: [NSNull null]] ? "never" : [zoneSetupOperation UTF8String]);
421 printf("viewSetupOperation: %s\n", [viewSetupOperation isEqual: [NSNull null]] ? "never" : [viewSetupOperation UTF8String]);
422 printf("keyStateOperation: %s\n", [keyStateOperation isEqual: [NSNull null]] ? "never" : [keyStateOperation UTF8String]);
423 printf("lastIncomingQueueOperation: %s\n", [lastIncomingQueueOperation isEqual: [NSNull null]] ? "never" : [lastIncomingQueueOperation UTF8String]);
424 printf("lastNewTLKOperation: %s\n", [lastNewTLKOperation isEqual: [NSNull null]] ? "never" : [lastNewTLKOperation UTF8String]);
425 printf("lastOutgoingQueueOperation: %s\n", [lastOutgoingQueueOperation isEqual: [NSNull null]] ? "never" : [lastOutgoingQueueOperation UTF8String]);
426 printf("lastRecordZoneChangesOperation: %s\n", [lastRecordZoneChangesOperation isEqual: [NSNull null]] ? "never" : [lastRecordZoneChangesOperation UTF8String]);
427 printf("lastProcessReceivedKeysOperation: %s\n", [lastProcessReceivedKeysOperation isEqual: [NSNull null]] ? "never" : [lastProcessReceivedKeysOperation UTF8String]);
428 printf("lastReencryptOutgoingItemsOperation: %s\n", [lastReencryptOutgoingItemsOperation isEqual: [NSNull null]] ? "never" : [lastReencryptOutgoingItemsOperation UTF8String]);
429 printf("lastScanLocalItemsOperation: %s\n", [lastScanLocalItemsOperation isEqual: [NSNull null]] ? "never" : [lastScanLocalItemsOperation UTF8String]);
430
431 if(status.allKeys.count > 0u) {
432 printf("\nExtra information: %s\n", [[status description] UTF8String]);
433 }
434 printf("\n");
435 }
436 dispatch_semaphore_signal(sema);
437 }];
438
439 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5)) != 0) {
440 printf("\n\nError: timed out waiting for response\n");
441 }
442 #endif // OCTAGON
443 }
444
445 - (void)fetch: (NSString*) view {
446 #if OCTAGON
447 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
448
449 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
450 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
451 dispatch_semaphore_signal(sema);
452
453 }] rpcFetchAndProcessChanges:view reply:^(NSError* error) {
454 if(error) {
455 printf("Error fetching: %s\n", [[error description] UTF8String]);
456 } else {
457 printf("Complete.\n");
458 }
459
460 dispatch_semaphore_signal(sema);
461 }];
462
463 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 65)) != 0) {
464 printf("\n\nError: timed out waiting for response\n");
465 }
466 #endif // OCTAGON
467 }
468
469 - (void)push: (NSString*) view {
470 #if OCTAGON
471 dispatch_semaphore_t sema = dispatch_semaphore_create(0);
472
473 [[self.connection remoteObjectProxyWithErrorHandler: ^(NSError* error) {
474 printf("\n\nError talking with daemon: %s\n", [[error description] UTF8String]);
475 dispatch_semaphore_signal(sema);
476
477 }] rpcPushOutgoingChanges:view reply:^(NSError* error) {
478 if(error) {
479 printf("Error pushing: %s\n", [[error description] UTF8String]);
480 } else {
481 printf("Complete.\n");
482 }
483
484 dispatch_semaphore_signal(sema);
485 }];
486
487 if(dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 65)) != 0) {
488 printf("\n\nError: timed out waiting for response\n");
489 }
490 #endif // OCTAGON
491 }
492
493 @end
494
495
496 static int perfCounters = false;
497 static int status = false;
498 static int resync = false;
499 static int reset = false;
500 static int resetCloudKit = false;
501 static int fetch = false;
502 static int push = false;
503 static int json = false;
504 static int getAnalyticsSysdiagnose = false;
505 static int getAnalyticsJSON = false;
506 static int uploadAnalytics = false;
507
508 static char* viewArg = NULL;
509
510 int main(int argc, char **argv)
511 {
512 static struct argument options[] = {
513 { .shortname='p', .longname="perfcounters", .flag=&perfCounters, .flagval=true, .description="Print CKKS performance counters"},
514 { .shortname='j', .longname="json", .flag=&json, .flagval=true, .description="Output in JSON format"},
515 { .shortname='v', .longname="view", .argument=&viewArg, .description="Operate on a single view"},
516
517 { .command="status", .flag=&status, .flagval=true, .description="Report status on CKKS views"},
518 { .command="fetch", .flag=&fetch, .flagval=true, .description="Fetch all new changes in CloudKit and attempt to process them"},
519 { .command="push", .flag=&push, .flagval=true, .description="Push all pending local changes to CloudKit"},
520 { .command="resync", .flag=&resync, .flagval=true, .description="Resync all data with what's in CloudKit"},
521 { .command="reset", .flag=&reset, .flagval=true, .description="All local data will be wiped, and data refetched from CloudKit"},
522 { .command="reset-cloudkit", .flag=&resetCloudKit, .flagval=true, .description="All data in CloudKit will be removed and replaced with what's local"},
523 { .command="get-analytics-sysdiagnose", .flag=&getAnalyticsSysdiagnose, .flagval=true, .description="Retrieve the current sysdiagnose dump for CKKS analytics"},
524 { .command="get-analytics", .flag=&getAnalyticsJSON, .flagval=true, .description="Retrieve the current JSON blob that would be uploaded to the logging server if an upload occurred now"},
525 { .command="upload-analytics", .flag=&uploadAnalytics, .flagval=true, .description="Force an upload of analytics data to cloud server"},
526 {}
527 };
528
529 static struct arguments args = {
530 .programname="ckksctl",
531 .description="Control and report on CKKS",
532 .arguments = options,
533 };
534
535 if(!options_parse(argc, argv, &args)) {
536 printf("\n");
537 print_usage(&args);
538 return -1;
539 }
540
541 @autoreleasepool {
542 xpc_endpoint_t endpoint = NULL;
543
544 CFErrorRef cferror = NULL;
545 endpoint = _SecSecuritydCopyCKKSEndpoint(&cferror);
546 if (endpoint == NULL) {
547 CFStringRef errorstr = NULL;
548
549 if(cferror) {
550 errorstr = CFErrorCopyDescription(cferror);
551 }
552
553 errx(1, "no CKKSControl endpoint available: %s", errorstr ? CFStringGetCStringPtr(errorstr, kCFStringEncodingUTF8) : "unknown error");
554 }
555
556 CKKSControl *ctl = [[CKKSControl alloc] initWithEndpoint:endpoint];
557 if (ctl == NULL) {
558 errx(1, "failed to create CKKSControl object");
559 }
560
561 NSString* view = viewArg ? [NSString stringWithCString: viewArg encoding: NSUTF8StringEncoding] : nil;
562
563 if(status || perfCounters) {
564 NSMutableDictionary *statusDict = [[NSMutableDictionary alloc] init];
565 statusDict[@"performance"] = [ctl printPerformanceCounters];
566 if (!json) {
567 print_result(statusDict, false);
568 if (status) {
569 [ctl status_custom:view];
570 }
571 } else {
572 if (status) {
573 statusDict[@"status"] = [ctl status:view];
574 }
575 print_result(statusDict, true);
576 }
577 } else if(fetch) {
578 [ctl fetch:view];
579 } else if(push) {
580 [ctl push:view];
581 } else if(reset) {
582 [ctl resetLocal:view];
583 } else if(resetCloudKit) {
584 [ctl resetCloudKit:view];
585 } else if(resync) {
586 [ctl resync:view];
587 } else if(getAnalyticsSysdiagnose) {
588 [ctl getAnalyticsSysdiagnose];
589 } else if(getAnalyticsJSON) {
590 [ctl getAnalyticsJSON];
591 } else if(uploadAnalytics) {
592 [ctl forceAnalyticsUpload];
593 } else {
594 print_usage(&args);
595 return -1;
596 }
597 }
598 return 0;
599 }