]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConfigurationInternal.c
configd-699.1.5.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConfigurationInternal.c
1 /*
2 * Copyright (c) 2004-2007, 2009, 2010, 2012, 2013 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 * Modification History
26 *
27 * May 27, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32 #include <CoreFoundation/CoreFoundation.h>
33 #include <SystemConfiguration/SystemConfiguration.h>
34 #include <SystemConfiguration/SCValidation.h>
35 #include <SystemConfiguration/SCPrivate.h>
36
37 #include <sys/ioctl.h>
38 #include <net/if.h>
39
40
41 __private_extern__ CFDictionaryRef
42 __getPrefsConfiguration(SCPreferencesRef prefs, CFStringRef path)
43 {
44 CFDictionaryRef config;
45 CFIndex n;
46
47 config = SCPreferencesPathGetValue(prefs, path);
48
49 n = isA_CFDictionary(config) ? CFDictionaryGetCount(config) : 0;
50 switch (n) {
51 case 0 :
52 // ignore empty configuration entities
53 config = NULL;
54 break;
55 case 1 :
56 if (CFDictionaryContainsKey(config, kSCResvInactive)) {
57 // ignore [effectively] empty configuration entities
58 config = NULL;
59 }
60 break;
61 default :
62 break;
63 }
64
65 return config;
66 }
67
68
69 __private_extern__ Boolean
70 __setPrefsConfiguration(SCPreferencesRef prefs,
71 CFStringRef path,
72 CFDictionaryRef config,
73 Boolean keepInactive)
74 {
75 CFDictionaryRef curConfig;
76 CFMutableDictionaryRef newConfig = NULL;
77 Boolean ok;
78
79 if ((config != NULL) && !isA_CFDictionary(config)) {
80 _SCErrorSet(kSCStatusInvalidArgument);
81 return FALSE;
82 }
83
84 curConfig = SCPreferencesPathGetValue(prefs, path);
85
86 if (config != NULL) {
87 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
88 }
89
90 if (keepInactive) {
91 if (config == NULL) {
92 newConfig = CFDictionaryCreateMutable(NULL,
93 0,
94 &kCFTypeDictionaryKeyCallBacks,
95 &kCFTypeDictionaryValueCallBacks);
96 }
97
98 if (isA_CFDictionary(curConfig) && CFDictionaryContainsKey(curConfig, kSCResvInactive)) {
99 // if currently disabled
100 CFDictionarySetValue(newConfig, kSCResvInactive, kCFBooleanTrue);
101 } else {
102 // if currently enabled
103 CFDictionaryRemoveValue(newConfig, kSCResvInactive);
104 }
105 }
106
107 // set new configuration
108 if (_SC_CFEqual(curConfig, newConfig)) {
109 // if no change
110 if (newConfig != NULL) CFRelease(newConfig);
111 ok = TRUE;
112 } else if (newConfig != NULL) {
113 // if new configuration (or we are preserving a disabled state)
114 ok = SCPreferencesPathSetValue(prefs, path, newConfig);
115 CFRelease(newConfig);
116 } else {
117 ok = SCPreferencesPathRemoveValue(prefs, path);
118 if (!ok && (SCError() == kSCStatusNoKey)) {
119 ok = TRUE;
120 }
121 }
122
123 return ok;
124 }
125
126
127 __private_extern__ Boolean
128 __getPrefsEnabled(SCPreferencesRef prefs, CFStringRef path)
129 {
130 CFDictionaryRef config;
131
132 config = SCPreferencesPathGetValue(prefs, path);
133 if (isA_CFDictionary(config) && CFDictionaryContainsKey(config, kSCResvInactive)) {
134 return FALSE;
135 }
136
137 return TRUE;
138 }
139
140
141 __private_extern__ Boolean
142 __setPrefsEnabled(SCPreferencesRef prefs,
143 CFStringRef path,
144 Boolean enabled)
145 {
146 CFDictionaryRef curConfig;
147 CFMutableDictionaryRef newConfig = NULL;
148 Boolean ok = FALSE;
149
150 // preserve current configuration
151 curConfig = SCPreferencesPathGetValue(prefs, path);
152 if (curConfig != NULL) {
153 if (!isA_CFDictionary(curConfig)) {
154 _SCErrorSet(kSCStatusFailed);
155 return FALSE;
156 }
157 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, curConfig);
158
159 if (enabled) {
160 // enable
161 CFDictionaryRemoveValue(newConfig, kSCResvInactive);
162 } else {
163 // disable
164 CFDictionarySetValue(newConfig, kSCResvInactive, kCFBooleanTrue);
165 }
166 } else {
167 if (!enabled) {
168 // disable
169 newConfig = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
170 CFDictionarySetValue(newConfig, kSCResvInactive, kCFBooleanTrue);
171 }
172 }
173
174 // set new configuration
175 if (_SC_CFEqual(curConfig, newConfig)) {
176 // if no change
177 if (newConfig != NULL) CFRelease(newConfig);
178 ok = TRUE;
179 } else if (newConfig != NULL) {
180 // if updated configuration (or we are establishing as disabled)
181 ok = SCPreferencesPathSetValue(prefs, path, newConfig);
182 CFRelease(newConfig);
183 } else {
184 ok = SCPreferencesPathRemoveValue(prefs, path);
185 if (!ok && (SCError() == kSCStatusNoKey)) {
186 ok = TRUE;
187 }
188 }
189
190 return ok;
191 }
192
193
194 static CFDictionaryRef
195 __copyTemplates()
196 {
197 CFBundleRef bundle;
198 CFErrorRef error = NULL;
199 Boolean ok;
200 CFDictionaryRef templates;
201 CFURLRef url;
202 CFDataRef xmlTemplates = NULL;
203
204 bundle = _SC_CFBundleGet();
205 if (bundle == NULL) {
206 return NULL;
207 }
208
209 url = CFBundleCopyResourceURL(bundle, CFSTR("NetworkConfiguration"), CFSTR("plist"), NULL);
210 if (url == NULL) {
211 return NULL;
212 }
213
214 #pragma GCC diagnostic push
215 #pragma GCC diagnostic ignored "-Wdeprecated"
216 ok = CFURLCreateDataAndPropertiesFromResource(NULL, url, &xmlTemplates, NULL, NULL, NULL);
217 #pragma GCC diagnostic pop
218 CFRelease(url);
219 if (!ok || (xmlTemplates == NULL)) {
220 return NULL;
221 }
222
223 // convert the XML data into a property list
224 templates = CFPropertyListCreateWithData(NULL, xmlTemplates, kCFPropertyListImmutable, NULL, &error);
225 CFRelease(xmlTemplates);
226 if (templates == NULL) {
227 if (error != NULL) {
228 SCLog(TRUE, LOG_DEBUG, CFSTR("could not load SCNetworkConfiguration templates: %@"), error);
229 CFRelease(error);
230 }
231 return NULL;
232 }
233
234 if (!isA_CFDictionary(templates)) {
235 CFRelease(templates);
236 return NULL;
237 }
238
239 return templates;
240 }
241
242
243 __private_extern__ CFDictionaryRef
244 __copyInterfaceTemplate(CFStringRef interfaceType,
245 CFStringRef childInterfaceType)
246 {
247 CFDictionaryRef interface = NULL;
248 CFDictionaryRef interfaces;
249 CFDictionaryRef templates;
250
251 templates = __copyTemplates();
252 if (templates == NULL) {
253 return NULL;
254 }
255
256 interfaces = CFDictionaryGetValue(templates, CFSTR("Interface"));
257 if (!isA_CFDictionary(interfaces)) {
258 CFRelease(templates);
259 return NULL;
260 }
261
262 if (childInterfaceType == NULL) {
263 interface = CFDictionaryGetValue(interfaces, interfaceType);
264 } else {
265 CFStringRef expandedType;
266
267 if (CFStringFind(childInterfaceType, CFSTR("."), 0).location != kCFNotFound) {
268 // if "vendor" type
269 childInterfaceType = CFSTR("*");
270 }
271
272 expandedType = CFStringCreateWithFormat(NULL,
273 NULL,
274 CFSTR("%@-%@"),
275 interfaceType,
276 childInterfaceType);
277 interface = CFDictionaryGetValue(interfaces, expandedType);
278 CFRelease(expandedType);
279 }
280
281 if (isA_CFDictionary(interface) && (CFDictionaryGetCount(interface) > 0)) {
282 CFRetain(interface);
283 } else {
284 interface = NULL;
285 }
286
287 CFRelease(templates);
288
289 return interface;
290 }
291
292
293 __private_extern__ CFDictionaryRef
294 __copyProtocolTemplate(CFStringRef interfaceType,
295 CFStringRef childInterfaceType,
296 CFStringRef protocolType)
297 {
298 CFDictionaryRef interface = NULL;
299 CFDictionaryRef protocol = NULL;
300 CFDictionaryRef protocols;
301 CFDictionaryRef templates;
302
303 templates = __copyTemplates();
304 if (templates == NULL) {
305 return NULL;
306 }
307
308 protocols = CFDictionaryGetValue(templates, CFSTR("Protocol"));
309 if (!isA_CFDictionary(protocols)) {
310 CFRelease(templates);
311 return NULL;
312 }
313
314 if (childInterfaceType == NULL) {
315 interface = CFDictionaryGetValue(protocols, interfaceType);
316 } else {
317 CFStringRef expandedType;
318
319 if (CFStringFind(childInterfaceType, CFSTR("."), 0).location != kCFNotFound) {
320 // if "vendor" type
321 childInterfaceType = CFSTR("*");
322 }
323
324 expandedType = CFStringCreateWithFormat(NULL,
325 NULL,
326 CFSTR("%@-%@"),
327 interfaceType,
328 childInterfaceType);
329 interface = CFDictionaryGetValue(protocols, expandedType);
330 CFRelease(expandedType);
331 }
332
333 if (isA_CFDictionary(interface)) {
334 protocol = CFDictionaryGetValue(interface, protocolType);
335 if (isA_CFDictionary(protocol)) {
336 CFRetain(protocol);
337 } else {
338 protocol = NULL;
339 }
340 }
341
342 CFRelease(templates);
343
344 return protocol;
345 }
346
347
348 __private_extern__ Boolean
349 __createInterface(int s, CFStringRef interface)
350 {
351 struct ifreq ifr;
352
353 bzero(&ifr, sizeof(ifr));
354 (void) _SC_cfstring_to_cstring(interface,
355 ifr.ifr_name,
356 sizeof(ifr.ifr_name),
357 kCFStringEncodingASCII);
358
359 if (ioctl(s, SIOCIFCREATE, &ifr) == -1) {
360 SCLog(TRUE,
361 LOG_ERR,
362 CFSTR("could not create interface \"%@\": %s"),
363 interface,
364 strerror(errno));
365 return FALSE;
366 }
367
368 return TRUE;
369 }
370
371
372 __private_extern__ Boolean
373 __destroyInterface(int s, CFStringRef interface)
374 {
375 struct ifreq ifr;
376
377 bzero(&ifr, sizeof(ifr));
378 (void) _SC_cfstring_to_cstring(interface,
379 ifr.ifr_name,
380 sizeof(ifr.ifr_name),
381 kCFStringEncodingASCII);
382
383 if (ioctl(s, SIOCIFDESTROY, &ifr) == -1) {
384 SCLog(TRUE,
385 LOG_ERR,
386 CFSTR("could not destroy interface \"%@\": %s"),
387 interface,
388 strerror(errno));
389 return FALSE;
390 }
391
392 return TRUE;
393 }
394
395
396 /*
397 * For rdar://problem/4685223
398 *
399 * To keep MoreSCF happy we need to ensure that the first "Set" and
400 * "NetworkService" have a [less than] unique identifier that can
401 * be parsed as a numeric string.
402 *
403 * Note: this backwards compatibility code must be enabled using the
404 * following command:
405 *
406 * sudo defaults write \
407 * /Library/Preferences/SystemConfiguration/preferences \
408 * MoreSCF \
409 * -bool true
410 */
411 __private_extern__
412 CFStringRef
413 __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs, CFStringRef prefix)
414 {
415 static int hack = -1;
416 CFStringRef path = NULL;
417
418 if (hack < 0) {
419 CFBooleanRef enable;
420
421 enable = SCPreferencesGetValue(prefs, CFSTR("MoreSCF"));
422 hack = (isA_CFBoolean(enable) && CFBooleanGetValue(enable)) ? 1 : 0;
423 }
424
425 if (hack > 0) {
426 CFDictionaryRef dict;
427 Boolean ok;
428
429 path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), prefix, CFSTR("0"));
430 dict = SCPreferencesPathGetValue(prefs, path);
431 if (dict != NULL) {
432 // if path "0" exists
433 CFRelease(path);
434 return NULL;
435 }
436
437 // unique child with path "0" does not exist, create
438 dict = CFDictionaryCreate(NULL,
439 NULL, NULL, 0,
440 &kCFTypeDictionaryKeyCallBacks,
441 &kCFTypeDictionaryValueCallBacks);
442 ok = SCPreferencesPathSetValue(prefs, path, dict);
443 CFRelease(dict);
444 if (!ok) {
445 // if create failed
446 CFRelease(path);
447 return NULL;
448 }
449 }
450
451 return path;
452 }
453
454
455 static CFDataRef
456 __copy_legacy_password(CFTypeRef password)
457 {
458 if (password == NULL) {
459 return NULL;
460 }
461
462 if (isA_CFData(password)) {
463 CFIndex n;
464
465 n = CFDataGetLength(password);
466 if ((n % sizeof(UniChar)) == 0) {
467 CFStringEncoding encoding;
468 CFStringRef str;
469
470 #if __BIG_ENDIAN__
471 encoding = (*(CFDataGetBytePtr(password) + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE;
472 #else // __LITTLE_ENDIAN__
473 encoding = (*(CFDataGetBytePtr(password) ) == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE;
474 #endif
475 str = CFStringCreateWithBytes(NULL,
476 (const UInt8 *)CFDataGetBytePtr(password),
477 n,
478 encoding,
479 FALSE);
480 password = CFStringCreateExternalRepresentation(NULL,
481 str,
482 kCFStringEncodingUTF8,
483 0);
484 CFRelease(str);
485 } else {
486 password = NULL;
487 }
488 } else if (isA_CFString(password) && (CFStringGetLength(password) > 0)) {
489 // convert password to CFData
490 password = CFStringCreateExternalRepresentation(NULL,
491 password,
492 kCFStringEncodingUTF8,
493 0);
494 } else {
495 password = NULL;
496 }
497
498 return password;
499 }
500
501
502 __private_extern__
503 Boolean
504 __extract_password(SCPreferencesRef prefs,
505 CFDictionaryRef config,
506 CFStringRef passwordKey,
507 CFStringRef encryptionKey,
508 CFStringRef encryptionKeyChainValue,
509 CFStringRef unique_id,
510 CFDataRef *password)
511 {
512 CFStringRef encryption = NULL;
513 Boolean exists = FALSE;
514
515 // check for keychain password
516 if (config != NULL) {
517 encryption = CFDictionaryGetValue(config, encryptionKey);
518 }
519 if ((encryption == NULL) ||
520 (isA_CFString(encryption) &&
521 CFEqual(encryption, encryptionKeyChainValue))) {
522 // check password
523 if (password != NULL) {
524 if (prefs != NULL) {
525 *password = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id);
526 } else {
527 *password = _SCSecKeychainPasswordItemCopy(NULL, unique_id);
528 }
529 exists = (*password != NULL);
530 } else {
531 if (prefs != NULL) {
532 exists = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id);
533 } else {
534 exists = _SCSecKeychainPasswordItemExists(NULL, unique_id);
535 }
536 }
537 }
538
539 // as needed, check for in-line password
540 if (!exists && (encryption == NULL) && (config != NULL)) {
541 CFDataRef inline_password;
542
543 inline_password = CFDictionaryGetValue(config, passwordKey);
544 inline_password = __copy_legacy_password(inline_password);
545 if (inline_password != NULL) {
546 exists = TRUE;
547
548 if (password != NULL) {
549 *password = inline_password;
550 } else {
551 CFRelease(inline_password);
552 }
553 }
554 }
555
556 return exists;
557 }
558
559
560 __private_extern__
561 Boolean
562 __remove_password(SCPreferencesRef prefs,
563 CFDictionaryRef config,
564 CFStringRef passwordKey,
565 CFStringRef encryptionKey,
566 CFStringRef encryptionKeyChainValue,
567 CFStringRef unique_id,
568 CFDictionaryRef *newConfig)
569 {
570 CFStringRef encryption = NULL;
571 Boolean ok = FALSE;
572
573 // check for keychain password
574 if (config != NULL) {
575 encryption = CFDictionaryGetValue(config, encryptionKey);
576 }
577 if ((encryption == NULL) ||
578 (isA_CFString(encryption) &&
579 CFEqual(encryption, encryptionKeyChainValue))) {
580 // remove keychain password
581 if (prefs != NULL) {
582 ok = _SCPreferencesSystemKeychainPasswordItemRemove(prefs, unique_id);
583 } else {
584 ok = _SCSecKeychainPasswordItemRemove(NULL, unique_id);
585 }
586 }
587
588 // as needed, check if we have an in-line password that we can remove
589 if (!ok && (encryption == NULL) && (config != NULL)) {
590 CFDataRef inline_password;
591
592 inline_password = CFDictionaryGetValue(config, passwordKey);
593 inline_password = __copy_legacy_password(inline_password);
594 if (inline_password != NULL) {
595 CFRelease(inline_password);
596 ok = TRUE;
597 }
598 }
599
600 if (newConfig != NULL) {
601 if (ok && (config != NULL)) {
602 CFMutableDictionaryRef temp;
603
604 temp = CFDictionaryCreateMutableCopy(NULL, 0, config);
605 CFDictionaryRemoveValue(temp, passwordKey);
606 CFDictionaryRemoveValue(temp, encryptionKey);
607 *newConfig = (CFDictionaryRef)temp;
608 } else {
609 *newConfig = NULL;
610 }
611 }
612
613 return ok;
614 }
615
616
617 __private_extern__ Boolean
618 __rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr)
619 {
620 switch (rank) {
621 case kSCNetworkServicePrimaryRankDefault :
622 *rankStr = NULL;
623 break;
624 case kSCNetworkServicePrimaryRankFirst :
625 *rankStr = kSCValNetServicePrimaryRankFirst;
626 break;
627 case kSCNetworkServicePrimaryRankLast :
628 *rankStr = kSCValNetServicePrimaryRankLast;
629 break;
630 case kSCNetworkServicePrimaryRankNever :
631 *rankStr = kSCValNetServicePrimaryRankNever;
632 break;
633 case kSCNetworkServicePrimaryRankScoped :
634 *rankStr = kSCValNetServicePrimaryRankScoped;
635 break;
636 default :
637 return FALSE;
638 }
639
640 return TRUE;
641 }
642
643
644 __private_extern__ Boolean
645 __str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank)
646 {
647 if (isA_CFString(rankStr)) {
648 if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) {
649 *rank = kSCNetworkServicePrimaryRankFirst;
650 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) {
651 *rank = kSCNetworkServicePrimaryRankLast;
652 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) {
653 *rank = kSCNetworkServicePrimaryRankNever;
654 } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankScoped)) {
655 *rank = kSCNetworkServicePrimaryRankScoped;
656 } else {
657 return FALSE;
658 }
659 } else if (rankStr == NULL) {
660 *rank = kSCNetworkServicePrimaryRankDefault;
661 } else {
662 return FALSE;
663 }
664
665 return TRUE;
666 }