]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConfigurationInternal.c
configd-204.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConfigurationInternal.c
1 /*
2 * Copyright (c) 2004-2007 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 Boolean ok;
191 CFDictionaryRef templates;
192 CFURLRef url;
193 CFStringRef xmlError = NULL;
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 = CFPropertyListCreateFromXMLData(NULL, xmlTemplates, kCFPropertyListImmutable, &xmlError);
214 CFRelease(xmlTemplates);
215 if (templates == NULL) {
216 if (xmlError != NULL) {
217 SCLog(TRUE, LOG_DEBUG, CFSTR("could not load SCNetworkConfiguration templates: %@"), xmlError);
218 CFRelease(xmlError);
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 expandedType = CFStringCreateWithFormat(NULL,
257 NULL,
258 CFSTR("%@-%@"),
259 interfaceType,
260 childInterfaceType);
261 interface = CFDictionaryGetValue(interfaces, expandedType);
262 CFRelease(expandedType);
263 }
264
265 if (isA_CFDictionary(interface) && (CFDictionaryGetCount(interface) > 0)) {
266 CFRetain(interface);
267 } else {
268 interface = NULL;
269 }
270
271 CFRelease(templates);
272
273 return interface;
274 }
275
276
277 __private_extern__ CFDictionaryRef
278 __copyProtocolTemplate(CFStringRef interfaceType,
279 CFStringRef childInterfaceType,
280 CFStringRef protocolType)
281 {
282 CFDictionaryRef interface = NULL;
283 CFDictionaryRef protocol = NULL;
284 CFDictionaryRef protocols;
285 CFDictionaryRef templates;
286
287 templates = __copyTemplates();
288 if (templates == NULL) {
289 return NULL;
290 }
291
292 protocols = CFDictionaryGetValue(templates, CFSTR("Protocol"));
293 if (!isA_CFDictionary(protocols)) {
294 CFRelease(templates);
295 return NULL;
296 }
297
298 if (childInterfaceType == NULL) {
299 interface = CFDictionaryGetValue(protocols, interfaceType);
300 } else {
301 CFStringRef expandedType;
302
303 expandedType = CFStringCreateWithFormat(NULL,
304 NULL,
305 CFSTR("%@-%@"),
306 interfaceType,
307 childInterfaceType);
308 interface = CFDictionaryGetValue(protocols, expandedType);
309 CFRelease(expandedType);
310 }
311
312 if (isA_CFDictionary(interface)) {
313 protocol = CFDictionaryGetValue(interface, protocolType);
314 if (isA_CFDictionary(protocol)) {
315 CFRetain(protocol);
316 } else {
317 protocol = NULL;
318 }
319 }
320
321 CFRelease(templates);
322
323 return protocol;
324 }
325
326
327 __private_extern__ Boolean
328 __createInterface(int s, CFStringRef interface)
329 {
330 struct ifreq ifr;
331
332 bzero(&ifr, sizeof(ifr));
333 (void) _SC_cfstring_to_cstring(interface,
334 ifr.ifr_name,
335 sizeof(ifr.ifr_name),
336 kCFStringEncodingASCII);
337
338 if (ioctl(s, SIOCIFCREATE, &ifr) == -1) {
339 SCLog(TRUE,
340 LOG_ERR,
341 CFSTR("could not create interface \"%@\": %s"),
342 interface,
343 strerror(errno));
344 return FALSE;
345 }
346
347 return TRUE;
348 }
349
350
351 __private_extern__ Boolean
352 __destroyInterface(int s, CFStringRef interface)
353 {
354 struct ifreq ifr;
355
356 bzero(&ifr, sizeof(ifr));
357 (void) _SC_cfstring_to_cstring(interface,
358 ifr.ifr_name,
359 sizeof(ifr.ifr_name),
360 kCFStringEncodingASCII);
361
362 if (ioctl(s, SIOCIFDESTROY, &ifr) == -1) {
363 SCLog(TRUE,
364 LOG_ERR,
365 CFSTR("could not destroy interface \"%@\": %s"),
366 interface,
367 strerror(errno));
368 return FALSE;
369 }
370
371 return TRUE;
372 }
373
374
375 /*
376 * For rdar://problem/4685223
377 *
378 * To keep MoreSCF happy we need to ensure that the first "Set" and
379 * "NetworkService" have a [less than] unique identifier that can
380 * be parsed as a numeric string.
381 *
382 * Note: this backwards compatibility code must be enabled using the
383 * following command:
384 *
385 * sudo defaults write \
386 * /Library/Preferences/SystemConfiguration/preferences \
387 * MoreSCF \
388 * -bool true
389 */
390 __private_extern__
391 CFStringRef
392 __SCPreferencesPathCreateUniqueChild_WithMoreSCFCompatibility(SCPreferencesRef prefs, CFStringRef prefix)
393 {
394 static int hack = -1;
395 CFStringRef path = NULL;
396
397 if (hack < 0) {
398 CFBooleanRef enable;
399
400 enable = SCPreferencesGetValue(prefs, CFSTR("MoreSCF"));
401 hack = (isA_CFBoolean(enable) && CFBooleanGetValue(enable)) ? 1 : 0;
402 }
403
404 if (hack > 0) {
405 CFDictionaryRef dict;
406 Boolean ok;
407
408 path = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@/%@"), prefix, CFSTR("0"));
409 dict = SCPreferencesPathGetValue(prefs, path);
410 if (dict != NULL) {
411 // if path "0" exists
412 CFRelease(path);
413 return NULL;
414 }
415
416 // unique child with path "0" does not exist, create
417 dict = CFDictionaryCreate(NULL,
418 NULL, NULL, 0,
419 &kCFTypeDictionaryKeyCallBacks,
420 &kCFTypeDictionaryValueCallBacks);
421 ok = SCPreferencesPathSetValue(prefs, path, dict);
422 CFRelease(dict);
423 if (!ok) {
424 // if create failed
425 CFRelease(path);
426 return NULL;
427 }
428 }
429
430 return path;
431 }
432
433
434 static CFDataRef
435 __copy_legacy_password(CFTypeRef password)
436 {
437 if (password == NULL) {
438 return NULL;
439 }
440
441 if (isA_CFData(password)) {
442 CFIndex n;
443
444 n = CFDataGetLength(password);
445 if ((n % sizeof(UniChar)) == 0) {
446 CFStringEncoding encoding;
447 CFStringRef str;
448
449 #if __BIG_ENDIAN__
450 encoding = (*(CFDataGetBytePtr(password) + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE;
451 #else // __LITTLE_ENDIAN__
452 encoding = (*(CFDataGetBytePtr(password) ) == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE;
453 #endif
454 str = CFStringCreateWithBytes(NULL,
455 (const UInt8 *)CFDataGetBytePtr(password),
456 n,
457 encoding,
458 FALSE);
459 password = CFStringCreateExternalRepresentation(NULL,
460 str,
461 kCFStringEncodingUTF8,
462 0);
463 CFRelease(str);
464 } else {
465 password = NULL;
466 }
467 } else if (isA_CFString(password) && (CFStringGetLength(password) > 0)) {
468 // convert password to CFData
469 password = CFStringCreateExternalRepresentation(NULL,
470 password,
471 kCFStringEncodingUTF8,
472 0);
473 } else {
474 password = NULL;
475 }
476
477 return password;
478 }
479
480
481 __private_extern__
482 Boolean
483 __extract_password(SCPreferencesRef prefs,
484 CFDictionaryRef config,
485 CFStringRef passwordKey,
486 CFStringRef encryptionKey,
487 CFStringRef encryptionKeyChainValue,
488 CFStringRef unique_id,
489 CFDataRef *password)
490 {
491 CFStringRef encryption = NULL;
492 Boolean exists = FALSE;
493
494 // check for keychain password
495 if (config != NULL) {
496 encryption = CFDictionaryGetValue(config, encryptionKey);
497 }
498 if ((encryption == NULL) ||
499 (isA_CFString(encryption) &&
500 CFEqual(encryption, encryptionKeyChainValue))) {
501 // check password
502 if (password != NULL) {
503 if (prefs != NULL) {
504 *password = _SCPreferencesSystemKeychainPasswordItemCopy(prefs, unique_id);
505 } else {
506 *password = _SCSecKeychainPasswordItemCopy(NULL, unique_id);
507 }
508 exists = (*password != NULL);
509 } else {
510 if (prefs != NULL) {
511 exists = _SCPreferencesSystemKeychainPasswordItemExists(prefs, unique_id);
512 } else {
513 exists = _SCSecKeychainPasswordItemExists(NULL, unique_id);
514 }
515 }
516 }
517
518 // as needed, check for in-line password
519 if (!exists && (encryption == NULL) && (config != NULL)) {
520 CFDataRef inline_password;
521
522 inline_password = CFDictionaryGetValue(config, passwordKey);
523 inline_password = __copy_legacy_password(inline_password);
524 if (inline_password != NULL) {
525 exists = TRUE;
526
527 if (password != NULL) {
528 *password = inline_password;
529 } else {
530 CFRelease(inline_password);
531 }
532 }
533 }
534
535 return exists;
536 }
537