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