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