]>
Commit | Line | Data |
---|---|---|
427c49bc A |
1 | /* |
2 | * Copyright (c) 2012 Apple Computer, 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 | // main.m | |
26 | // ckd-xpc | |
27 | // | |
28 | // Created by John Hurley on 7/19/12. | |
29 | // Copyright (c) 2012 John Hurley. All rights reserved. | |
30 | // | |
31 | ||
32 | /* | |
33 | This XPC service is essentially just a proxy to iCloud KVS, which exists since | |
34 | the main security code cannot link against Foundation. | |
35 | ||
36 | See sendTSARequestWithXPC in tsaSupport.c for how to call the service | |
37 | ||
38 | send message to app with xpc_connection_send_message | |
39 | ||
40 | For now, build this with: | |
41 | ||
42 | ~rc/bin/buildit . --rootsDirectory=/var/tmp -noverify -offline -target CloudKeychainProxy | |
43 | ||
44 | and install or upgrade with: | |
45 | ||
46 | darwinup install /var/tmp/sec.roots/sec~dst | |
47 | darwinup upgrade /var/tmp/sec.roots/sec~dst | |
48 | ||
49 | You must use darwinup during development to update system caches | |
50 | */ | |
51 | ||
52 | //------------------------------------------------------------------------------------------------ | |
53 | ||
54 | #include <AssertMacros.h> | |
55 | ||
56 | #import <Foundation/Foundation.h> | |
57 | #import <Security/Security.h> | |
58 | #import <utilities/SecCFRelease.h> | |
59 | #import <xpc/xpc.h> | |
60 | #import <xpc/private.h> | |
61 | #import <CoreFoundation/CFXPCBridge.h> | |
62 | #import <sysexits.h> | |
63 | #import <syslog.h> | |
64 | #import <CommonCrypto/CommonDigest.h> | |
65 | #include <utilities/SecXPCError.h> | |
66 | ||
67 | #import "SOSCloudKeychainConstants.h" | |
68 | #import "CKDKVSProxy.h" | |
69 | ||
70 | void finalize_connection(void *not_used); | |
71 | void handle_connection_event(const xpc_connection_t peer); | |
72 | static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t peer, xpc_object_t event); | |
73 | ||
74 | static bool operation_put_dictionary(xpc_object_t event); | |
75 | static bool operation_get_v2(xpc_object_t event); | |
76 | ||
77 | int ckdproxymain(int argc, const char *argv[]); | |
78 | ||
79 | static void describeXPCObject(char *prefix, xpc_object_t object) | |
80 | { | |
81 | //#ifndef NDEBUG | |
82 | // This is useful for debugging. | |
83 | if (object) | |
84 | { | |
85 | char *desc = xpc_copy_description(object); | |
86 | secdebug(XPROXYSCOPE, "%s%s\n", prefix, desc); | |
87 | free(desc); | |
88 | } | |
89 | else | |
90 | secdebug(XPROXYSCOPE, "%s<NULL>\n", prefix); | |
91 | ||
92 | //#endif | |
93 | } | |
94 | ||
95 | static void cloudkeychainproxy_peer_dictionary_handler(const xpc_connection_t peer, xpc_object_t event) | |
96 | { | |
97 | bool result = false; | |
98 | int err = 0; | |
99 | ||
100 | require_action_string(xpc_get_type(event) == XPC_TYPE_DICTIONARY, xit, err = -51, "expected XPC_TYPE_DICTIONARY"); | |
101 | ||
102 | const char *operation = xpc_dictionary_get_string(event, kMessageKeyOperation); | |
103 | require_action(operation, xit, result = false); | |
104 | ||
105 | // Check protocol version | |
106 | uint64_t version = xpc_dictionary_get_uint64(event, kMessageKeyVersion); | |
107 | secdebug(XPROXYSCOPE, "Reply version: %lld\n", version); | |
108 | require_action(version == kCKDXPCVersion, xit, result = false); | |
109 | ||
110 | // Operations | |
111 | secdebug(XPROXYSCOPE, "Handling %s operation", operation); | |
112 | ||
113 | if (operation && !strcmp(operation, kOperationPUTDictionary)) | |
114 | operation_put_dictionary(event); | |
115 | else | |
116 | if (operation && !strcmp(operation, kOperationGETv2)) | |
117 | operation_get_v2(event); | |
118 | else | |
119 | if (operation && !strcmp(operation, kOperationClearStore)) | |
120 | { | |
121 | [[UbiqitousKVSProxy sharedKVSProxy] clearStore]; | |
122 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
123 | if (replyMessage) // Caller wanted an ACK, so give one | |
124 | { | |
125 | xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK"); | |
126 | xpc_connection_send_message(peer, replyMessage); | |
127 | } | |
128 | } | |
129 | else if (operation && !strcmp(operation, kOperationRemoveObjectForKey)) | |
130 | { | |
131 | const char *keyToRemove = xpc_dictionary_get_string(event, kMessageKeyKey); | |
132 | [[UbiqitousKVSProxy sharedKVSProxy] removeObjectForKey:[NSString stringWithCString:keyToRemove encoding:NSUTF8StringEncoding]]; | |
133 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
134 | if (replyMessage) // Caller wanted an ACK, so give one | |
135 | { | |
136 | xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK"); | |
137 | xpc_connection_send_message(peer, replyMessage); | |
138 | } | |
139 | } | |
140 | else if (operation && !strcmp(operation, kOperationSynchronize)) | |
141 | { | |
142 | [[UbiqitousKVSProxy sharedKVSProxy] requestSynchronization:YES]; | |
143 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
144 | if (replyMessage) // Caller wanted an ACK, so give one | |
145 | { | |
146 | xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK"); | |
147 | xpc_connection_send_message(peer, replyMessage); | |
148 | } | |
149 | } | |
150 | else if (operation && !strcmp(operation, kOperationSynchronizeAndWait)) | |
151 | { | |
152 | xpc_object_t xkeysToGetDict = xpc_dictionary_get_value(event, kMessageKeyValue); | |
153 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
154 | xpc_object_t xkeys = xpc_dictionary_get_value(xkeysToGetDict, kMessageKeyKeysToGet); | |
155 | NSArray *keysToGet = (__bridge NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xkeys)); | |
156 | [[UbiqitousKVSProxy sharedKVSProxy] waitForSynchronization:keysToGet | |
157 | handler:^(NSDictionary *values, NSError *err) { | |
158 | if (replyMessage) // Caller wanted an ACK, so give one | |
159 | { | |
160 | secdebug("keytrace", "Result from [[UbiqitousKVSProxy sharedKVSProxy] waitForSynchronization:]: %@", err); | |
161 | xpc_object_t xobject = values ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)(values)) : xpc_null_create(); | |
162 | xpc_dictionary_set_value(replyMessage, kMessageKeyValue, xobject); | |
163 | if (err) | |
164 | { | |
165 | xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((CFErrorRef)CFBridgingRetain(err)); | |
166 | xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj); | |
167 | CFReleaseSafe((__bridge CFTypeRef)(err)); | |
168 | } | |
169 | xpc_connection_send_message(peer, replyMessage); | |
170 | } | |
171 | }]; | |
172 | CFReleaseSafe((__bridge CFTypeRef)(keysToGet)); | |
173 | } | |
174 | else if (operation && !strcmp(operation, kOperationRegisterKeysAndGet)) | |
175 | { | |
176 | xpc_object_t xkeysToRegisterDict = xpc_dictionary_get_value(event, kMessageKeyValue); | |
177 | // describeXPCObject("xkeysToRegister: ", xkeysToRegisterDict); | |
178 | // KTR = keysToRegister | |
179 | bool getNewKeysOnly = xpc_dictionary_get_bool(xkeysToRegisterDict, kMessageKeyGetNewKeysOnly); | |
180 | xpc_object_t xKTRallkeys = xpc_dictionary_get_value(xkeysToRegisterDict, kMessageKeyKeysToGet); | |
181 | xpc_object_t xKTRrequiresFirstUnlock = xpc_dictionary_get_value(xkeysToRegisterDict, kMessageKeyKeysRequireFirstUnlock); | |
182 | xpc_object_t xKTRrequiresUnlock = xpc_dictionary_get_value(xkeysToRegisterDict, kMessageKeyKeysRequiresUnlocked); | |
183 | ||
184 | NSArray *KTRallkeys = (__bridge NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xKTRallkeys)); | |
185 | NSArray *KTRrequiresFirstUnlock = (__bridge NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xKTRrequiresFirstUnlock)); | |
186 | NSArray *KTRrequiresUnlock = (__bridge NSArray *)(_CFXPCCreateCFObjectFromXPCObject(xKTRrequiresUnlock)); | |
187 | ||
188 | id object = [[UbiqitousKVSProxy sharedKVSProxy] registerKeysAndGet:getNewKeysOnly always:KTRallkeys reqFirstUnlock:KTRrequiresFirstUnlock reqUnlocked:KTRrequiresUnlock]; | |
189 | ||
190 | CFReleaseSafe((__bridge CFTypeRef)(KTRallkeys)); | |
191 | CFReleaseSafe((__bridge CFTypeRef)(KTRrequiresFirstUnlock)); | |
192 | CFReleaseSafe((__bridge CFTypeRef)(KTRrequiresUnlock)); | |
193 | ||
194 | secdebug("keytrace", "Result from [[UbiqitousKVSProxy sharedKVSProxy] registerKeysAndGet:]: %@", object); | |
195 | ||
196 | xpc_object_t xobject = object ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)(object)) : xpc_null_create(); | |
197 | ||
198 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
199 | xpc_dictionary_set_value(replyMessage, kMessageKeyValue, xobject); | |
200 | xpc_connection_send_message(peer, replyMessage); | |
201 | secdebug(XPROXYSCOPE, "RegisterKeysAndGet message sent"); | |
202 | } | |
203 | else if (operation && !strcmp(operation, kOperationUILocalNotification)) | |
204 | { | |
205 | xpc_object_t xLocalNotificationDict = xpc_dictionary_get_value(event, kMessageKeyValue); | |
206 | // describeXPCObject("xLocalNotificationDict: ", xLocalNotificationDict); | |
207 | NSDictionary *localNotificationDict = (__bridge NSDictionary *)(_CFXPCCreateCFObjectFromXPCObject(xLocalNotificationDict)); | |
208 | int64_t outFlags = 0; | |
209 | id object = [[UbiqitousKVSProxy sharedKVSProxy] localNotification:localNotificationDict outFlags:&outFlags]; | |
210 | secdebug(XPROXYSCOPE, "Result from [[UbiqitousKVSProxy sharedKVSProxy] localNotification:]: %@", object); | |
211 | xpc_object_t xobject = object ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)(object)) : xpc_null_create(); | |
212 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
213 | xpc_dictionary_set_int64(xobject, kMessageKeyNotificationFlags, outFlags); | |
214 | xpc_dictionary_set_value(replyMessage, kMessageKeyValue, xobject); | |
215 | xpc_connection_send_message(peer, replyMessage); | |
216 | secdebug(XPROXYSCOPE, "localNotification reply sent"); | |
217 | CFReleaseSafe((__bridge CFTypeRef)(localNotificationDict)); | |
218 | } | |
219 | else if (operation && !strcmp(operation, kOperationSetParams)) | |
220 | { | |
221 | xpc_object_t xParamsDict = xpc_dictionary_get_value(event, kMessageKeyValue); | |
222 | NSDictionary *paramsDict = (__bridge NSDictionary *)(_CFXPCCreateCFObjectFromXPCObject(xParamsDict)); | |
223 | [[UbiqitousKVSProxy sharedKVSProxy] setParams:paramsDict]; | |
224 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
225 | if (replyMessage) // Caller wanted an ACK, so give one | |
226 | { | |
227 | xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK"); | |
228 | xpc_connection_send_message(peer, replyMessage); | |
229 | } | |
230 | secdebug(XPROXYSCOPE, "setParams reply sent"); | |
231 | CFReleaseSafe((__bridge CFTypeRef)(paramsDict)); | |
232 | } | |
233 | else if (operation && !strcmp(operation, kOperationRequestSyncWithAllPeers)) | |
234 | { | |
235 | [[UbiqitousKVSProxy sharedKVSProxy] requestSyncWithAllPeers]; | |
236 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
237 | if (replyMessage) // Caller wanted an ACK, so give one | |
238 | { | |
239 | xpc_dictionary_set_string(replyMessage, kMessageKeyValue, "ACK"); | |
240 | xpc_connection_send_message(peer, replyMessage); | |
241 | } | |
242 | secdebug(XPROXYSCOPE, "RequestSyncWithAllPeers reply sent"); | |
243 | } | |
244 | else | |
245 | { | |
246 | char *description = xpc_copy_description(event); | |
247 | secdebug(XPROXYSCOPE, "Unknown op=%s request from pid %d: %s", operation, xpc_connection_get_pid(peer), description); | |
248 | free(description); | |
249 | } | |
250 | result = true; | |
251 | xit: | |
252 | if (!result) | |
253 | describeXPCObject("handle_operation fail: ", event); | |
254 | } | |
255 | ||
256 | void finalize_connection(void *not_used) | |
257 | { | |
258 | secdebug(XPROXYSCOPE, "finalize_connection"); | |
259 | [[UbiqitousKVSProxy sharedKVSProxy] requestSynchronization:YES]; | |
260 | xpc_transaction_end(); | |
261 | } | |
262 | ||
263 | static bool operation_put_dictionary(xpc_object_t event) | |
264 | { | |
265 | // PUT a set of objects into the KVS store. Return false if error | |
266 | ||
267 | describeXPCObject("operation_put_dictionary event: ", event); | |
268 | xpc_object_t xvalue = xpc_dictionary_get_value(event, kMessageKeyValue); | |
269 | if (!xvalue) | |
270 | return false; | |
271 | ||
272 | CFTypeRef cfvalue = _CFXPCCreateCFObjectFromXPCObject(xvalue); | |
273 | if (cfvalue && (CFGetTypeID(cfvalue)==CFDictionaryGetTypeID())) | |
274 | { | |
275 | [[UbiqitousKVSProxy sharedKVSProxy] setObjectsFromDictionary:(__bridge NSDictionary *)cfvalue]; | |
276 | CFReleaseSafe(cfvalue); | |
277 | return true; | |
278 | } | |
279 | else{ | |
280 | describeXPCObject("operation_put_dictionary unable to convert to CF: ", xvalue); | |
281 | CFReleaseSafe(cfvalue); | |
282 | } | |
283 | return false; | |
284 | } | |
285 | ||
286 | static bool operation_get_v2(xpc_object_t event) | |
287 | { | |
288 | // GET a set of objects from the KVS store. Return false if error | |
289 | describeXPCObject("operation_get_v2 event: ", event); | |
290 | xpc_connection_t peer = xpc_dictionary_get_remote_connection(event); | |
291 | describeXPCObject("operation_get_v2: peer: ", peer); | |
292 | ||
293 | xpc_object_t replyMessage = xpc_dictionary_create_reply(event); | |
294 | if (!replyMessage) | |
295 | { | |
296 | secdebug(XPROXYSCOPE, "can't create replyMessage"); | |
297 | assert(true); //must have a reply handler | |
298 | return false; | |
299 | } | |
300 | xpc_object_t returnedValues = xpc_dictionary_create(NULL, NULL, 0); | |
301 | if (!returnedValues) | |
302 | { | |
303 | secdebug(XPROXYSCOPE, "can't create returnedValues"); | |
304 | assert(true); // must have a spot for the returned values | |
305 | return false; | |
306 | } | |
307 | ||
308 | xpc_object_t xvalue = xpc_dictionary_get_value(event, kMessageKeyValue); | |
309 | if (!xvalue) | |
310 | { | |
311 | secdebug(XPROXYSCOPE, "missing \"value\" key"); | |
312 | return false; | |
313 | } | |
314 | ||
315 | xpc_object_t xkeystoget = xpc_dictionary_get_value(xvalue, kMessageKeyKeysToGet); | |
316 | if (xkeystoget) | |
317 | { | |
318 | secdebug(XPROXYSCOPE, "got xkeystoget"); | |
319 | CFTypeRef keystoget = _CFXPCCreateCFObjectFromXPCObject(xkeystoget); | |
320 | if (!keystoget || (CFGetTypeID(keystoget)!=CFArrayGetTypeID())) // not "getAll", this is an error of some kind | |
321 | { | |
322 | secdebug(XPROXYSCOPE, "can't convert keystoget or is not an array"); | |
323 | CFReleaseSafe(keystoget); | |
324 | return false; | |
325 | } | |
326 | ||
327 | [(__bridge NSArray *)keystoget enumerateObjectsUsingBlock: ^ (id obj, NSUInteger idx, BOOL *stop) | |
328 | { | |
329 | NSString *key = (NSString *)obj; | |
330 | id object = [[UbiqitousKVSProxy sharedKVSProxy] get:key]; | |
331 | secdebug(XPROXYSCOPE, "[UbiqitousKVSProxy sharedKVSProxy] get: key: %@, object: %@", key, object); | |
332 | xpc_object_t xobject = object ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)object) : xpc_null_create(); | |
333 | xpc_dictionary_set_value(returnedValues, [key UTF8String], xobject); | |
334 | describeXPCObject("operation_get_v2: value from kvs: ", xobject); | |
335 | }]; | |
336 | } | |
337 | else // get all values from kvs | |
338 | { | |
339 | secdebug(XPROXYSCOPE, "get all values from kvs"); | |
340 | NSDictionary *all = [[UbiqitousKVSProxy sharedKVSProxy] getAll]; | |
341 | [all enumerateKeysAndObjectsUsingBlock: ^ (id key, id obj, BOOL *stop) | |
342 | { | |
343 | xpc_object_t xobject = obj ? _CFXPCCreateXPCObjectFromCFObject((__bridge CFTypeRef)obj) : xpc_null_create(); | |
344 | xpc_dictionary_set_value(returnedValues, [(NSString *)key UTF8String], xobject); | |
345 | }]; | |
346 | } | |
347 | ||
348 | xpc_dictionary_set_uint64(replyMessage, kMessageKeyVersion, kCKDXPCVersion); | |
349 | xpc_dictionary_set_value(replyMessage, kMessageKeyValue, returnedValues); | |
350 | xpc_connection_send_message(peer, replyMessage); | |
351 | ||
352 | return true; | |
353 | } | |
354 | ||
355 | static void initializeProxyObjectWithConnection(const xpc_connection_t connection) | |
356 | { | |
357 | [[UbiqitousKVSProxy sharedKVSProxy] setItemsChangedBlock:^(CFDictionaryRef values) | |
358 | { | |
359 | secdebug(XPROXYSCOPE, "UbiqitousKVSProxy called back"); | |
360 | xpc_object_t xobj = _CFXPCCreateXPCObjectFromCFObject(values); | |
361 | xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0); | |
362 | xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion); | |
363 | xpc_dictionary_set_string(message, kMessageKeyOperation, kMessageOperationItemChanged); | |
364 | xpc_dictionary_set_value(message, kMessageKeyValue, xobj?xobj:xpc_null_create()); | |
365 | xpc_connection_send_message(connection, message); // Send message; don't wait for a reply | |
366 | }]; | |
367 | } | |
368 | ||
369 | static void cloudkeychainproxy_peer_event_handler(xpc_connection_t peer, xpc_object_t event) | |
370 | { | |
371 | describeXPCObject("peer: ", peer); | |
372 | xpc_type_t type = xpc_get_type(event); | |
373 | if (type == XPC_TYPE_ERROR) { | |
374 | if (event == XPC_ERROR_CONNECTION_INVALID) { | |
375 | // The client process on the other end of the connection has either | |
376 | // crashed or cancelled the connection. After receiving this error, | |
377 | // the connection is in an invalid state, and you do not need to | |
378 | // call xpc_connection_cancel(). Just tear down any associated state | |
379 | // here. | |
380 | } else if (event == XPC_ERROR_TERMINATION_IMMINENT) { | |
381 | // Handle per-connection termination cleanup. | |
382 | } | |
383 | } else { | |
384 | assert(type == XPC_TYPE_DICTIONARY); | |
385 | // Handle the message. | |
386 | // describeXPCObject("dictionary:", event); | |
387 | cloudkeychainproxy_peer_dictionary_handler(peer, event); | |
388 | } | |
389 | } | |
390 | ||
391 | static void cloudkeychainproxy_event_handler(xpc_connection_t peer) | |
392 | { | |
393 | // By defaults, new connections will target the default dispatch | |
394 | // concurrent queue. | |
395 | ||
396 | if (xpc_get_type(peer) != XPC_TYPE_CONNECTION) | |
397 | { | |
398 | secdebug(XPROXYSCOPE, "expected XPC_TYPE_CONNECTION"); | |
399 | return; | |
400 | } | |
401 | initializeProxyObjectWithConnection(peer); | |
402 | xpc_connection_set_event_handler(peer, ^(xpc_object_t event) | |
403 | { | |
404 | cloudkeychainproxy_peer_event_handler(peer, event); | |
405 | }); | |
406 | ||
407 | // This will tell the connection to begin listening for events. If you | |
408 | // have some other initialization that must be done asynchronously, then | |
409 | // you can defer this call until after that initialization is done. | |
410 | xpc_connection_resume(peer); | |
411 | } | |
412 | ||
413 | static void diagnostics(int argc, const char *argv[]) | |
414 | { | |
415 | @autoreleasepool | |
416 | { | |
417 | NSDictionary *all = [[UbiqitousKVSProxy sharedKVSProxy] getAll]; | |
418 | NSLog(@"All: %@",all); | |
419 | } | |
420 | } | |
421 | ||
422 | int ckdproxymain(int argc, const char *argv[]) | |
423 | { | |
424 | secdebug(XPROXYSCOPE, "Starting CloudKeychainProxy"); | |
425 | char *wait4debugger = getenv("WAIT4DEBUGGER"); | |
426 | if (wait4debugger && !strcasecmp("YES", wait4debugger)) | |
427 | { | |
428 | syslog(LOG_ERR, "Waiting for debugger"); | |
429 | kill(getpid(), SIGSTOP); | |
430 | } | |
431 | ||
432 | if (argc > 1) { | |
433 | diagnostics(argc, argv); | |
434 | return 0; | |
435 | } | |
436 | ||
437 | #if !TARGET_IPHONE_SIMULATOR | |
438 | xpc_track_activity(); // sets us up for idle timeout handling | |
439 | #endif | |
440 | ||
441 | // DISPATCH_TARGET_QUEUE_DEFAULT | |
442 | xpc_connection_t listener = xpc_connection_create_mach_service(xpcServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); | |
443 | xpc_connection_set_event_handler(listener, ^(xpc_object_t object){ cloudkeychainproxy_event_handler(object); }); | |
444 | ||
445 | [UbiqitousKVSProxy sharedKVSProxy]; | |
446 | ||
447 | // It looks to me like there is insufficient locking to allow a request to come in on the XPC connection while doing the initial all items. | |
448 | // Therefore I'm leaving the XPC connection suspended until that has time to process. | |
449 | xpc_connection_resume(listener); | |
450 | ||
451 | @autoreleasepool | |
452 | { | |
453 | secdebug(XPROXYSCOPE, "Starting mainRunLoop"); | |
454 | NSRunLoop *runLoop = [NSRunLoop mainRunLoop]; | |
455 | [runLoop run]; | |
456 | } | |
457 | ||
458 | secdebug(XPROXYSCOPE, "Exiting CloudKeychainProxy"); | |
459 | ||
460 | return EXIT_FAILURE; | |
461 | } |