]> git.saurik.com Git - apple/configd.git/blob - libSystemConfiguration/libSystemConfiguration_server.c
configd-1061.0.2.tar.gz
[apple/configd.git] / libSystemConfiguration / libSystemConfiguration_server.c
1 /*
2 * Copyright (c) 2012-2018 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 <TargetConditionals.h>
25 #include <dispatch/dispatch.h>
26 #include <vproc.h>
27 #include <vproc_priv.h>
28 #include <xpc/xpc.h>
29 #include <xpc/private.h>
30
31 #include <CoreFoundation/CoreFoundation.h>
32 #include <SystemConfiguration/SCPrivate.h>
33 #include "libSystemConfiguration_server.h"
34
35 #define kTrailingEdgeAgentEntitlement "com.apple.SystemConfiguration.trailing-edge-agent"
36
37 #ifdef SC_LOG_HANDLE
38 #include <os/log.h>
39 os_log_t SC_LOG_HANDLE(void);
40 #endif //SC_LOG_HANDLE
41
42
43 #pragma mark -
44 #pragma mark client connection trackng
45
46
47 typedef struct {
48 xpc_connection_t connection;
49 } client_key_t;
50
51 typedef struct {
52 pid_t pid;
53 uint64_t generation_pushed;
54 uint64_t generation_acknowledged;
55 } client_val_t;
56
57
58 static __inline__ CF_RETURNS_RETAINED CFDataRef
59 _client_key(xpc_connection_t c)
60 {
61 client_key_t key;
62 CFDataRef client_key;
63
64 key.connection = c;
65 client_key = CFDataCreate(NULL, (UInt8 *)&key, sizeof(key));
66 return client_key;
67 }
68
69
70 static void
71 _handle_entitlement_check_failure(pid_t pid)
72 {
73 static Boolean cleanupScheduled = FALSE;
74 static dispatch_once_t initializer = 0;
75 static CFMutableArrayRef pids = NULL;
76 static dispatch_queue_t queue = NULL;
77
78 dispatch_once(&initializer, ^{
79 pids = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
80 queue = dispatch_queue_create("handle unentitled ack", NULL);
81 });
82
83 dispatch_sync(queue, ^{
84 CFNumberRef pidNumber = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &pid);
85
86 if (!CFArrayContainsValue(pids, CFRangeMake(0, CFArrayGetCount(pids)), pidNumber)) {
87 CFArrayAppendValue(pids, pidNumber);
88
89 SC_log(LOG_INFO, "DNS/nwi dropping ack w/no entitlement, pid = %d", pid);
90
91 if (!cleanupScheduled) {
92 cleanupScheduled = TRUE;
93 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 180LL * NSEC_PER_SEC), queue, ^{
94 CFArrayRemoveAllValues(pids);
95 cleanupScheduled = FALSE;
96 });
97 }
98 }
99
100 CFRelease(pidNumber);
101 });
102 }
103
104
105 /*
106 * libSystemConfiguraiton_client
107 *
108 * - all APIs must be called from the same [serial] dispatch queue
109 */
110
111
112 __private_extern__
113 void
114 _libSC_info_server_init(libSC_info_server_t *server_info) {
115 memset(server_info, 0, sizeof(*server_info));
116 server_info->info = CFDictionaryCreateMutable(NULL,
117 0,
118 &kCFTypeDictionaryKeyCallBacks,
119 &kCFTypeDictionaryValueCallBacks);
120 return;
121 }
122
123
124 __private_extern__
125 void
126 _libSC_info_server_set_data(libSC_info_server_t *server_info,
127 CFDataRef data,
128 uint64_t generation)
129 {
130 // update stored configuration
131 if (server_info->data != NULL) {
132 CFRelease(server_info->data);
133 server_info->data = NULL;
134 }
135 if (data != NULL) {
136 CFRetain(data);
137 server_info->data = data;
138 }
139
140 // update generation
141 if (generation == 0) {
142 // generation must be non-zero
143 generation = 1;
144 }
145 server_info->generation = generation;
146
147 // new configuration, all ack'ing clients need to
148 // check-in again
149 server_info->inSync_NO += server_info->inSync_YES;
150 server_info->inSync_YES = 0;
151
152 return;
153 }
154
155
156 /*
157 * _libSC_info_server_in_sync
158 *
159 * Called to check if all of the "active" configuration [XPC] connection
160 * are in sync with the requested generation.
161 */
162 __private_extern__
163 Boolean
164 _libSC_info_server_in_sync(libSC_info_server_t *server_info)
165 {
166 return (server_info->inSync_NO == 0) ? TRUE : FALSE;
167 }
168
169
170 /*
171 * _libSC_info_server_open
172 *
173 * Called when a new configuration [XPC] connection
174 * is established.
175 *
176 * - tracks the last generation pushed to the caller and
177 * the last generation ack'd by the caller
178 */
179 __private_extern__
180 void
181 _libSC_info_server_open(libSC_info_server_t *server_info,
182 xpc_connection_t c)
183 {
184 CFDataRef client_key;
185 CFMutableDataRef client_val;
186 client_val_t *val;
187
188 client_key = _client_key(c);
189
190 client_val = CFDataCreateMutable(NULL, sizeof(*val));
191 CFDataSetLength(client_val, sizeof(*val));
192
193 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val);
194 val->pid = xpc_connection_get_pid(c);
195 val->generation_pushed = 0;
196 val->generation_acknowledged = 0;
197
198 CFDictionarySetValue(server_info->info, client_key, client_val);
199 CFRelease(client_key);
200 CFRelease(client_val);
201
202 return;
203 }
204
205
206 /*
207 * _libSC_info_server_get_data
208 *
209 * Called when a [XPC] connection wants the current configuration.
210 *
211 * - updates the last generation pushed to the caller
212 */
213 __private_extern__
214 CFDataRef
215 _libSC_info_server_get_data(libSC_info_server_t *server_info,
216 xpc_connection_t c,
217 uint64_t *generation)
218 {
219 CFDataRef client_key;
220 CFMutableDataRef client_val;
221 client_val_t *val;
222
223 // update last generation pushed to client
224 client_key = _client_key(c);
225 client_val = (CFMutableDataRef)CFDictionaryGetValue(server_info->info, client_key);
226 CFRelease(client_key);
227
228 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val);
229 val->generation_pushed = server_info->generation;
230
231 // return generation
232 *generation = server_info->generation;
233 if (*generation == 1) {
234 *generation = 0;
235 }
236
237 // return data
238 return server_info->data;
239 }
240
241
242 /*
243 * _libSC_info_server_acknowledged
244 *
245 * Called when a [XPC] connection wants to acknowledge a
246 * processed configuration.
247 *
248 * - updates the last generation ack'd by the caller
249 * - updates the count of [XPC] connections that are / not in sync
250 */
251 __private_extern__
252 Boolean
253 _libSC_info_server_acknowledged(libSC_info_server_t *server_info,
254 xpc_connection_t c,
255 uint64_t generation)
256 {
257 CFDataRef client_key;
258 CFMutableDataRef client_val;
259 xpc_object_t ent_value;
260 Boolean entitled = FALSE;
261 Boolean sync_updated = FALSE;
262 client_val_t *val;
263
264 ent_value = xpc_connection_copy_entitlement_value(c, kTrailingEdgeAgentEntitlement);
265 if (ent_value != NULL) {
266 if (xpc_get_type(ent_value) == XPC_TYPE_BOOL) {
267 entitled = xpc_bool_get_value(ent_value);
268 }
269 xpc_release(ent_value);
270 }
271
272 if (!entitled) {
273 _handle_entitlement_check_failure(xpc_connection_get_pid(c));
274 return FALSE;
275 }
276
277 client_key = _client_key(c);
278 client_val = (CFMutableDataRef)CFDictionaryGetValue(server_info->info, client_key);
279 CFRelease(client_key);
280
281 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val);
282
283 if (val->generation_acknowledged == 0) {
284 // if first ack
285 if (generation == server_info->generation) {
286 server_info->inSync_YES++;
287 } else {
288 server_info->inSync_NO++;
289 sync_updated = TRUE;
290 }
291 } else if ((generation != val->generation_acknowledged) &&
292 (generation == server_info->generation)) {
293 // if we've previously ack'd a configuration
294 // ... and if we are ack'ing a configuration
295 // that we have not previously ack'd
296 // ... and if we're ack'ing the current stored
297 // configuration
298 server_info->inSync_NO--;
299 server_info->inSync_YES++;
300 sync_updated = TRUE;
301 }
302
303 val->generation_acknowledged = generation;
304
305 return sync_updated;
306 }
307
308
309 /*
310 * _libSC_info_server_close
311 *
312 * Called when a configuration [XPC] connection is closed.
313 */
314 __private_extern__
315 Boolean
316 _libSC_info_server_close(libSC_info_server_t *server_info,
317 xpc_connection_t c)
318 {
319 CFDataRef client_key;
320 CFMutableDataRef client_val;
321 Boolean sync_updated = FALSE;
322
323 client_key = _client_key(c);
324
325 // get client info, remove ack'd info
326 client_val = (CFMutableDataRef)CFDictionaryGetValue(server_info->info, client_key);
327 if (client_val != NULL) {
328 client_val_t *val;
329
330 val = (client_val_t *)(void *)CFDataGetMutableBytePtr(client_val);
331 if (val->generation_acknowledged > 0) {
332 // if we've previously ack'd a configuration
333 if (val->generation_acknowledged == server_info->generation) {
334 // if currently in sync
335 server_info->inSync_YES--;
336 } else {
337 // if currently NOT in sync
338 server_info->inSync_NO--;
339 sync_updated = TRUE;
340 }
341 }
342 }
343
344 CFDictionaryRemoveValue(server_info->info, client_key);
345 CFRelease(client_key);
346
347 return sync_updated;
348 }
349