]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkSignature.c
configd-963.200.27.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkSignature.c
1 /*
2 * Copyright (c) 2006, 2008, 2009, 2011-2015, 2017, 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 /*
25 * SCNetworkSignature.c
26 * - implementation of SCNetworkSignatureRef API that allows access to
27 network identification information
28 *
29 */
30 /*
31 * Modification History
32 *
33 * November 6, 2006 Dieter Siegmund (dieter@apple.com)
34 * - initial revision
35 */
36
37
38 #include <netinet/in.h>
39 #include <CoreFoundation/CFDictionary.h>
40 #include <CoreFoundation/CFString.h>
41 #include <CoreFoundation/CFArray.h>
42 #include <CoreFoundation/CFRuntime.h>
43 #include <SystemConfiguration/SCDynamicStore.h>
44 #include <SystemConfiguration/SCValidation.h>
45 #include <SystemConfiguration/SCPrivate.h>
46 #include "SCNetworkSignature.h"
47 #include "SCNetworkSignaturePrivate.h"
48 #include <arpa/inet.h>
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <net/if.h>
52 #if __has_include(<nw/private.h>)
53 #include <nw/private.h>
54 #else // __has_include(<nw/private.h>)
55 #include <network/conninfo.h>
56 #endif // __has_include(<nw/private.h>)
57
58 #pragma mark SCNetworkSignature Supporting APIs
59
60 static CFStringRef
61 create_global_state_v4_key(void)
62 {
63 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
64 kSCDynamicStoreDomainState,
65 kSCEntNetIPv4);
66
67 }
68
69 static CFStringRef
70 create_global_setup_v4_key(void)
71 {
72 return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
73 kSCDynamicStoreDomainSetup,
74 kSCEntNetIPv4);
75 }
76
77 static CFStringRef
78 create_ipv4_services_pattern(void)
79 {
80 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
81 kSCDynamicStoreDomainState,
82 kSCCompAnyRegex,
83 kSCEntNetIPv4);
84 }
85
86 static CFStringRef
87 create_ipv6_services_pattern(void)
88 {
89 return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
90 kSCDynamicStoreDomainState,
91 kSCCompAnyRegex,
92 kSCEntNetIPv6);
93 }
94
95 static CFDictionaryRef
96 copy_services_for_address_family(CFAllocatorRef alloc, int af)
97 {
98 #pragma unused(alloc)
99 CFDictionaryRef info;
100 CFArrayRef patterns;
101 CFStringRef pattern;
102 CFStringRef prop;
103
104 prop = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6;
105 pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
106 kSCDynamicStoreDomainState,
107 kSCCompAnyRegex,
108 prop);
109 patterns = CFArrayCreate(NULL,
110 (const void * *)&pattern, 1,
111 &kCFTypeArrayCallBacks);
112 CFRelease(pattern);
113 info = SCDynamicStoreCopyMultiple(NULL, NULL, patterns);
114 CFRelease(patterns);
115
116 return (info);
117 }
118
119
120 static CF_RETURNS_RETAINED CFStringRef
121 my_IPAddressToCFString(int af, const void * src_p)
122 {
123 char ntopbuf[INET6_ADDRSTRLEN];
124
125 if (inet_ntop(af, src_p, ntopbuf, sizeof(ntopbuf)) != NULL) {
126 return (CFStringCreateWithCString(NULL, ntopbuf,
127 kCFStringEncodingASCII));
128 }
129 return (NULL);
130 }
131
132 #pragma mark -
133
134
135 #pragma mark SCNetworkSignature APIs
136
137 CFStringRef
138 SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc,
139 const struct sockaddr * addr)
140 {
141 #pragma unused(alloc)
142 CFStringRef ident = NULL;
143 CFDictionaryRef info = NULL;
144 CFStringRef global_state_v4_key = NULL;
145 CFDictionaryRef global_v4_state_dict = NULL;
146 CFArrayRef keys = NULL;
147 CFArrayRef patterns = NULL;
148 in_addr_t s_addr;
149 CFStringRef service = NULL;
150 CFDictionaryRef service_dict = NULL;
151 CFStringRef service_id = NULL;
152 struct sockaddr_in * sin_p;
153 CFStringRef v4_service_pattern = NULL;
154
155 /* only accept 0.0.0.0 (i.e. default) for now */
156 if (addr == NULL
157 || addr->sa_family != AF_INET
158 || addr->sa_len != sizeof(struct sockaddr_in)) {
159 _SCErrorSet(kSCStatusInvalidArgument);
160 goto done;
161 }
162
163 /* ALIGN: force alignment */
164 sin_p = (struct sockaddr_in *)(void *)addr;
165 bcopy(&sin_p->sin_addr.s_addr, &s_addr, sizeof(s_addr));
166 if (s_addr != 0) {
167 _SCErrorSet(kSCStatusInvalidArgument);
168 goto done;
169 }
170
171 global_state_v4_key = create_global_state_v4_key();
172 keys = CFArrayCreate(NULL, (const void * *)&global_state_v4_key,
173 1, &kCFTypeArrayCallBacks);
174
175 v4_service_pattern = create_ipv4_services_pattern();
176 patterns = CFArrayCreate(NULL, (const void * *)&v4_service_pattern, 1,
177 &kCFTypeArrayCallBacks);
178
179 info = SCDynamicStoreCopyMultiple(NULL, keys, patterns);
180
181 if (info == NULL
182 || CFDictionaryGetCount(info) == 0) {
183 goto done;
184 }
185
186 global_v4_state_dict = CFDictionaryGetValue(info, global_state_v4_key);
187
188 if (isA_CFDictionary(global_v4_state_dict) == NULL) {
189 goto done;
190 }
191
192 service_id = CFDictionaryGetValue(global_v4_state_dict,
193 kSCDynamicStorePropNetPrimaryService);
194
195 if (isA_CFString(service_id) == NULL) {
196 goto done;
197 }
198
199 service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
200 kSCDynamicStoreDomainState,
201 service_id, kSCEntNetIPv4);
202
203 service_dict = CFDictionaryGetValue(info, service);
204
205
206 if (isA_CFDictionary(service_dict) == NULL
207 || CFDictionaryGetCount(service_dict) == 0) {
208 goto done;
209 }
210
211 ident = CFDictionaryGetValue(service_dict, kStoreKeyNetworkSignature);
212 ident = isA_CFString(ident);
213 done:
214 if (ident != NULL) {
215 CFRetain(ident);
216 } else {
217 _SCErrorSet(kSCStatusFailed);
218 }
219 if (info != NULL) {
220 CFRelease(info);
221 }
222 if (global_state_v4_key != NULL) {
223 CFRelease(global_state_v4_key);
224 }
225 if (service != NULL) {
226 CFRelease(service);
227 }
228 if (keys != NULL) {
229 CFRelease(keys);
230 }
231 if (patterns != NULL) {
232 CFRelease(patterns);
233 }
234 if (v4_service_pattern != NULL) {
235 CFRelease(v4_service_pattern);
236 }
237 return (ident);
238 }
239
240 CFArrayRef /* of CFStringRef's */
241 SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc)
242 {
243 #pragma unused(alloc)
244 CFMutableArrayRef active = NULL;
245 CFIndex count = 0;
246 CFStringRef global_setup_v4_key = NULL;
247 CFDictionaryRef global_v4_dict;
248 int i;
249 CFDictionaryRef info = NULL;
250 CFArrayRef keys = NULL;
251 CFMutableArrayRef patterns = NULL;
252 CFRange range;
253 CFMutableDictionaryRef services_dict = NULL;
254 CFArrayRef service_order;
255 CFStringRef v4_service_pattern = NULL;
256 CFStringRef v6_service_pattern = NULL;
257 const void * * values = NULL;
258 #define KEYS_STATIC_COUNT 10
259 const void * values_static[KEYS_STATIC_COUNT];
260
261 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
262
263 global_setup_v4_key = create_global_setup_v4_key();
264 keys = CFArrayCreate(NULL, (const void * *)&global_setup_v4_key, 1,
265 &kCFTypeArrayCallBacks);
266
267 v4_service_pattern = create_ipv4_services_pattern();
268 CFArrayAppendValue(patterns, v4_service_pattern);
269
270 v6_service_pattern = create_ipv6_services_pattern();
271 CFArrayAppendValue(patterns, v6_service_pattern);
272
273 info = SCDynamicStoreCopyMultiple(NULL, keys, patterns);
274
275 if (info == NULL
276 || CFDictionaryGetCount(info) == 0) {
277 goto done;
278 }
279
280 services_dict = CFDictionaryCreateMutableCopy(NULL, 0, info);
281 /*
282 * The service_dict should only contain services and once each
283 * service has been visited, it will be removed from the dictionary.
284 */
285 CFDictionaryRemoveValue(services_dict, global_setup_v4_key);
286
287 global_v4_dict = CFDictionaryGetValue(info, global_setup_v4_key);
288
289 if (isA_CFDictionary(global_v4_dict) != NULL) {
290 service_order = CFDictionaryGetValue(global_v4_dict,
291 kSCPropNetServiceOrder);
292 if (isA_CFArray(service_order) != NULL) {
293 count = CFArrayGetCount(service_order);
294 }
295 }
296
297 active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
298
299 range = CFRangeMake(0, 0);
300
301 for (i = 0; i < count ; i++) {
302 int j;
303 CFStringRef network_sig;
304 CFStringRef service;
305 CFStringRef service_id;
306 CFDictionaryRef service_info;
307 CFStringRef afs[2] = {kSCEntNetIPv4, kSCEntNetIPv6};
308
309 service_id = CFArrayGetValueAtIndex(service_order, i);
310
311 if (isA_CFString(service_id) == NULL) {
312 continue;
313 }
314
315 for (j = 0; j < 2; j++) {
316 service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
317 kSCDynamicStoreDomainState,
318 service_id, afs[j]);
319
320 service_info = CFDictionaryGetValue(services_dict, service);
321
322 /* Does this service have a signature? */
323 if (isA_CFDictionary(service_info) != NULL) {
324 network_sig = CFDictionaryGetValue(service_info, kStoreKeyNetworkSignature);
325 if (isA_CFString(network_sig) && !CFArrayContainsValue(active, range, network_sig)) {
326 CFArrayAppendValue(active, network_sig);
327 network_sig = NULL;
328 range.length++;
329 }
330 CFDictionaryRemoveValue(services_dict, service);
331 }
332 CFRelease(service);
333 }
334 }
335
336 count = CFDictionaryGetCount(services_dict);
337 if (count != 0) {
338 if (count > KEYS_STATIC_COUNT) {
339 values = (const void * *)malloc(sizeof(*values) * count);
340 } else {
341 values = values_static;
342 }
343 CFDictionaryGetKeysAndValues(services_dict, NULL,
344 (const void * *)values);
345 }
346
347 for (i = 0; i < count; i++) {
348 CFStringRef network_sig;
349 CFDictionaryRef service_dict = (CFDictionaryRef)values[i];
350
351 if (isA_CFDictionary(service_dict) == NULL) {
352 continue;
353 }
354
355 network_sig = CFDictionaryGetValue(service_dict,
356 kStoreKeyNetworkSignature);
357 /* Does this service have a signature? */
358 if (isA_CFString(network_sig) && !CFArrayContainsValue(active, range, network_sig)) {
359 CFArrayAppendValue(active, network_sig);
360 range.length++;
361 network_sig = NULL;
362 }
363 }
364 done:
365 if (info != NULL) {
366 CFRelease(info);
367 }
368 if (services_dict != NULL) {
369 CFRelease(services_dict);
370 }
371 if (global_setup_v4_key != NULL) {
372 CFRelease(global_setup_v4_key);
373 }
374 if (v4_service_pattern != NULL) {
375 CFRelease(v4_service_pattern);
376 }
377 if (v6_service_pattern != NULL) {
378 CFRelease(v6_service_pattern);
379 }
380 if (values != NULL && values != values_static) {
381 free(values);
382 }
383 if (keys != NULL) {
384 CFRelease(keys);
385 }
386 if (patterns != NULL) {
387 CFRelease(patterns);
388 }
389 if (active != NULL && CFArrayGetCount(active) == 0) {
390 CFRelease(active);
391 active = NULL;
392 }
393 if (active == NULL) {
394 _SCErrorSet(kSCStatusFailed);
395 }
396 return (active);
397 }
398
399
400 CFStringRef
401 SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc,
402 int sock_fd)
403 {
404 CFStringRef addresses_key;
405 int af;
406 CFIndex count;
407 int i;
408 char if_name[IFNAMSIZ];
409 CFStringRef if_name_cf = NULL;
410 conninfo_t * info = NULL;
411 const void * * keys = NULL;
412 #define KEYS_STATIC_COUNT 10
413 const void * keys_static[KEYS_STATIC_COUNT];
414 const void * local_ip_p;
415 CFStringRef local_ip_str = NULL;
416 CFStringRef ret_signature = NULL;
417 CFDictionaryRef service_info = NULL;
418 int status = kSCStatusFailed;
419
420 if (copyconninfo(sock_fd, SAE_CONNID_ANY, &info) != 0) {
421 status = kSCStatusInvalidArgument;
422 goto done;
423 }
424 if ((info->ci_flags & CIF_CONNECTED) == 0
425 || info->ci_src == NULL) {
426 goto done;
427 }
428 af = info->ci_src->sa_family;
429 switch (af) {
430 case AF_INET:
431 addresses_key = kSCPropNetIPv4Addresses;
432 local_ip_p = &((struct sockaddr_in *)
433 (void *)info->ci_src)->sin_addr;
434 break;
435 case AF_INET6:
436 addresses_key = kSCPropNetIPv6Addresses;
437 local_ip_p = &((struct sockaddr_in6 *)
438 (void *)info->ci_src)->sin6_addr;
439 break;
440 default:
441 status = kSCStatusInvalidArgument;
442 goto done;
443 }
444
445 /* search for service with matching IP address and interface name */
446 service_info = copy_services_for_address_family(alloc, af);
447 if (service_info == NULL) {
448 goto done;
449 }
450 local_ip_str = my_IPAddressToCFString(af, local_ip_p);
451 if (local_ip_str == NULL) {
452 goto done;
453 }
454 if (info->ci_ifindex != 0
455 && if_indextoname(info->ci_ifindex, if_name) != NULL) {
456 if_name_cf
457 = CFStringCreateWithCString(NULL, if_name,
458 kCFStringEncodingASCII);
459 }
460 count = CFDictionaryGetCount(service_info);
461 if (count > KEYS_STATIC_COUNT) {
462 keys = (const void * *)malloc(sizeof(*keys) * count);
463 }
464 else {
465 keys = keys_static;
466 }
467 CFDictionaryGetKeysAndValues(service_info, keys, NULL);
468 for (i = 0; i < count; i++) {
469 CFArrayRef addrs;
470 CFRange range;
471 CFStringRef signature;
472 CFDictionaryRef value;
473
474 value = CFDictionaryGetValue(service_info, keys[i]);
475 if (isA_CFDictionary(value) == NULL) {
476 continue;
477 }
478 signature = CFDictionaryGetValue(value,
479 kStoreKeyNetworkSignature);
480 if (isA_CFString(signature) == NULL) {
481 /* no signature */
482 continue;
483 }
484 if (if_name_cf != NULL) {
485 CFStringRef confirmed_if;
486 CFStringRef this_if;
487
488 this_if = CFDictionaryGetValue(value,
489 kSCPropInterfaceName);
490 if (isA_CFString(this_if) == NULL
491 || !CFEqual(this_if, if_name_cf)) {
492 /* no interface or it doesn't match */
493 continue;
494 }
495 confirmed_if
496 = CFDictionaryGetValue(value,
497 kSCPropConfirmedInterfaceName);
498 if (isA_CFString(confirmed_if) != NULL
499 && !CFEqual(confirmed_if, if_name_cf)) {
500 /* confirmed interface doesn't match */
501 continue;
502 }
503 }
504
505 addrs = CFDictionaryGetValue(value, addresses_key);
506 if (isA_CFArray(addrs) == NULL) {
507 continue;
508 }
509 range = CFRangeMake(0, CFArrayGetCount(addrs));
510 if (CFArrayContainsValue(addrs, range, local_ip_str)) {
511 ret_signature = CFRetain(signature);
512 status = kSCStatusOK;
513 break;
514 }
515 }
516
517 done:
518 if (info != NULL) {
519 freeconninfo(info);
520 }
521 if (if_name_cf != NULL) {
522 CFRelease(if_name_cf);
523 }
524 if (local_ip_str != NULL) {
525 CFRelease(local_ip_str);
526 }
527 if (keys != NULL && keys != keys_static) {
528 free(keys);
529 }
530 if (service_info != NULL) {
531 CFRelease(service_info);
532 }
533 if (status != kSCStatusOK) {
534 _SCErrorSet(status);
535 }
536 return (ret_signature);
537 }
538
539 #pragma mark -