]> git.saurik.com Git - apple/security.git/blob - OSX/sec/SOSCircle/IDSKeychainSyncingProxy/idskeychainsyncingproxy.m
Security-57337.60.2.tar.gz
[apple/security.git] / OSX / sec / SOSCircle / IDSKeychainSyncingProxy / idskeychainsyncingproxy.m
1 /*
2 * Copyright (c) 2012-2014 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 #include <AssertMacros.h>
25
26 #import <Foundation/Foundation.h>
27 #import <Security/Security.h>
28 #import <utilities/SecCFRelease.h>
29 #import <xpc/xpc.h>
30 #import <xpc/private.h>
31 #import <CoreFoundation/CFXPCBridge.h>
32 #import <sysexits.h>
33 #import <syslog.h>
34 #import <CommonCrypto/CommonDigest.h>
35 #include <utilities/SecXPCError.h>
36 #include <TargetConditionals.h>
37 #include "SOSCloudKeychainConstants.h"
38
39
40 #import "IDSProxy.h"
41
42 int idsproxymain(int argc, const char *argv[]);
43
44 #define PROXYXPCSCOPE "idsproxy"
45
46 static void describeXPCObject(char *prefix, xpc_object_t object)
47 {
48 // This is useful for debugging.
49 if (object)
50 {
51 char *desc = xpc_copy_description(object);
52 secdebug(PROXYXPCSCOPE, "%s%s\n", prefix, desc);
53 free(desc);
54 }
55 else
56 secdebug(PROXYXPCSCOPE, "%s<NULL>\n", prefix);
57
58 }
59
60 static void idskeychainsyncingproxy_peer_dictionary_handler(const xpc_connection_t peer, xpc_object_t event)
61 {
62 bool result = false;
63 int err = 0;
64
65 require_action_string(xpc_get_type(event) == XPC_TYPE_DICTIONARY, xit, err = -51, "expected XPC_TYPE_DICTIONARY");
66
67 const char *operation = xpc_dictionary_get_string(event, kMessageKeyOperation);
68 require_action(operation, xit, result = false);
69
70 // Check protocol version
71 uint64_t version = xpc_dictionary_get_uint64(event, kMessageKeyVersion);
72 secdebug(PROXYXPCSCOPE, "Reply version: %lld\n", version);
73 require_action(version == kCKDXPCVersion, xit, result = false);
74
75 // Operations
76 secdebug(PROXYXPCSCOPE, "Handling %s operation", operation);
77
78
79 if(operation && !strcmp(operation, kOperationGetDeviceID)){
80 NSError *error;
81 BOOL object = [[IDSKeychainSyncingProxy idsProxy] doSetIDSDeviceID:&error];
82 xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
83 xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, object);
84
85 if(error){
86 xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((__bridge CFErrorRef)(error));
87 xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj);
88 }
89 xpc_connection_send_message(peer, replyMessage);
90 secdebug(PROXYXPCSCOPE, "Set our IDS Device ID message sent");
91
92 }
93 else if (operation && !strcmp(operation, kOperationSendIDSMessage))
94 {
95 xpc_object_t xidsMessageData = xpc_dictionary_get_value(event, kMessageKeyValue);
96 xpc_object_t xDeviceName = xpc_dictionary_get_value(event, kMessageKeyDeviceName);
97 xpc_object_t xPeerID = xpc_dictionary_get_value(event, kMessageKeyPeerID);
98
99 NSString *deviceName = (__bridge_transfer NSString*)(_CFXPCCreateCFObjectFromXPCObject(xDeviceName));
100 NSString *peerID = (__bridge_transfer NSString*)(_CFXPCCreateCFObjectFromXPCObject(xPeerID));
101 NSDictionary *messageDictionary = (__bridge_transfer NSDictionary*)(_CFXPCCreateCFObjectFromXPCObject(xidsMessageData));
102 NSError *error = NULL;
103 bool isNameString = (CFGetTypeID((__bridge CFTypeRef)(deviceName)) == CFStringGetTypeID());
104 bool isPeerIDString = (CFGetTypeID((__bridge CFTypeRef)(peerID)) == CFStringGetTypeID());
105 bool isMessageDictionary = (CFGetTypeID((__bridge CFTypeRef)(messageDictionary)) == CFDictionaryGetTypeID());
106
107 require_quiet(isNameString, xit);
108 require_quiet(isPeerIDString, xit);
109 require_quiet(isMessageDictionary, xit);
110
111 BOOL object = [[IDSKeychainSyncingProxy idsProxy] sendIDSMessage:messageDictionary name:deviceName peer:peerID error:&error];
112
113 xpc_object_t replyMessage = xpc_dictionary_create_reply(event);
114 xpc_dictionary_set_bool(replyMessage, kMessageKeyValue, object);
115
116 if(error){
117 xpc_object_t xerrobj = SecCreateXPCObjectWithCFError((__bridge CFErrorRef)(error));
118 xpc_dictionary_set_value(replyMessage, kMessageKeyError, xerrobj);
119 }
120 xpc_connection_send_message(peer, replyMessage);
121 secdebug(PROXYXPCSCOPE, "IDS message sent");
122
123 }
124 else
125 {
126 char *description = xpc_copy_description(event);
127 secdebug(PROXYXPCSCOPE, "Unknown op=%s request from pid %d: %s", operation, xpc_connection_get_pid(peer), description);
128 free(description);
129 }
130 result = true;
131 xit:
132 if (!result)
133 describeXPCObject("handle_operation fail: ", event);
134 }
135
136
137 static void initializeProxyObjectWithConnection(const xpc_connection_t connection)
138 {
139 [[IDSKeychainSyncingProxy idsProxy] setItemsChangedBlock:^CFArrayRef(CFDictionaryRef values)
140 {
141 secdebug(PROXYXPCSCOPE, "IDSKeychainSyncingProxy called back");
142 xpc_object_t xobj = _CFXPCCreateXPCObjectFromCFObject(values);
143 xpc_object_t message = xpc_dictionary_create(NULL, NULL, 0);
144 xpc_dictionary_set_uint64(message, kMessageKeyVersion, kCKDXPCVersion);
145 xpc_dictionary_set_string(message, kMessageKeyOperation, kMessageOperationItemChanged);
146 xpc_dictionary_set_value(message, kMessageKeyValue, xobj?xobj:xpc_null_create());
147 xpc_connection_send_message(connection, message); // Send message; don't wait for a reply
148 return NULL;
149 }];
150 }
151
152 static void idskeychainsyncingproxy_peer_event_handler(xpc_connection_t peer, xpc_object_t event)
153 {
154 describeXPCObject("peer: ", peer);
155 xpc_type_t type = xpc_get_type(event);
156 if (type == XPC_TYPE_ERROR) {
157 if (event == XPC_ERROR_CONNECTION_INVALID) {
158 // The client process on the other end of the connection has either
159 // crashed or cancelled the connection. After receiving this error,
160 // the connection is in an invalid state, and you do not need to
161 // call xpc_connection_cancel(). Just tear down any associated state
162 // here.
163 } else if (event == XPC_ERROR_TERMINATION_IMMINENT) {
164 // Handle per-connection termination cleanup.
165 }
166 } else {
167 assert(type == XPC_TYPE_DICTIONARY);
168 // Handle the message.
169 // describeXPCObject("dictionary:", event);
170 dispatch_async(dispatch_get_main_queue(), ^{
171 idskeychainsyncingproxy_peer_dictionary_handler(peer, event);
172 });
173 }
174 }
175
176 static void idskeychainsyncingproxy_event_handler(xpc_connection_t peer)
177 {
178 // By defaults, new connections will target the default dispatch
179 // concurrent queue.
180
181 if (xpc_get_type(peer) != XPC_TYPE_CONNECTION)
182 {
183 secdebug(PROXYXPCSCOPE, "expected XPC_TYPE_CONNECTION");
184 return;
185 }
186 initializeProxyObjectWithConnection(peer);
187 xpc_connection_set_event_handler(peer, ^(xpc_object_t event)
188 {
189 idskeychainsyncingproxy_peer_event_handler(peer, event);
190 });
191
192 // This will tell the connection to begin listening for events. If you
193 // have some other initialization that must be done asynchronously, then
194 // you can defer this call until after that initialization is done.
195 xpc_connection_resume(peer);
196 }
197
198 int idsproxymain(int argc, const char *argv[])
199 {
200 secdebug(PROXYXPCSCOPE, "Starting IDSProxy");
201 char *wait4debugger = getenv("WAIT4DEBUGGER");
202
203 if (wait4debugger && !strcasecmp("YES", wait4debugger))
204 {
205 syslog(LOG_ERR, "Waiting for debugger");
206 kill(getpid(), SIGTSTP);
207 }
208
209 // DISPATCH_TARGET_QUEUE_DEFAULT
210 xpc_connection_t listener = xpc_connection_create_mach_service(xpcIDSServiceName, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
211 xpc_connection_set_event_handler(listener, ^(xpc_object_t object){ idskeychainsyncingproxy_event_handler(object); });
212
213 [IDSKeychainSyncingProxy idsProxy];
214
215 // 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.
216 // Therefore I'm leaving the XPC connection suspended until that has time to process.
217 xpc_connection_resume(listener);
218
219 @autoreleasepool
220 {
221 secdebug(PROXYXPCSCOPE, "Starting mainRunLoop");
222 NSRunLoop *runLoop = [NSRunLoop mainRunLoop];
223 [runLoop run];
224 }
225
226 secdebug(PROXYXPCSCOPE, "Exiting IDSKeychainSyncingProxy");
227
228 return EXIT_FAILURE;
229 }