]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConnectionPrivate.c
configd-293.4.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConnectionPrivate.c
1 /*
2 * Copyright (c) 2006-2009 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 #include <CoreFoundation/CoreFoundation.h>
25 #include <CoreFoundation/CFRuntime.h>
26 #include <SystemConfiguration/SystemConfiguration.h>
27 #include <SystemConfiguration/SCPrivate.h> // for SCLog
28 #include "SCNetworkConfigurationInternal.h"
29 #include <notify.h>
30 #include <pthread.h>
31
32
33 #pragma mark -
34 #pragma mark SCUserPreferences
35
36
37 typedef struct {
38
39 // base CFType information
40 CFRuntimeBase cfBase;
41
42 // serviceID
43 CFStringRef serviceID;
44
45 // user preferences [unique] id
46 CFStringRef prefsID;
47
48 } SCUserPreferencesPrivate, *SCUserPreferencesPrivateRef;
49
50
51 static CFStringRef __SCUserPreferencesCopyDescription (CFTypeRef cf);
52 static void __SCUserPreferencesDeallocate (CFTypeRef cf);
53 static Boolean __SCUserPreferencesEqual (CFTypeRef cf1, CFTypeRef cf2);
54 static CFHashCode __SCUserPreferencesHash (CFTypeRef cf);
55
56
57 static CFTypeID __kSCUserPreferencesTypeID = _kCFRuntimeNotATypeID;
58
59
60 static const CFRuntimeClass __SCUserPreferencesClass = {
61 0, // version
62 "SCUserPreferences", // className
63 NULL, // init
64 NULL, // copy
65 __SCUserPreferencesDeallocate, // dealloc
66 __SCUserPreferencesEqual, // equal
67 __SCUserPreferencesHash, // hash
68 NULL, // copyFormattingDesc
69 __SCUserPreferencesCopyDescription // copyDebugDesc
70 };
71
72
73 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
74
75
76 static CFStringRef
77 __SCUserPreferencesCopyDescription(CFTypeRef cf)
78 {
79 CFAllocatorRef allocator = CFGetAllocator(cf);
80 CFMutableStringRef result;
81 SCUserPreferencesPrivateRef prefsPrivate = (SCUserPreferencesPrivateRef)cf;
82
83 result = CFStringCreateMutable(allocator, 0);
84 CFStringAppendFormat(result, NULL, CFSTR("<SCUserPreferences %p [%p]> {"), cf, allocator);
85 CFStringAppendFormat(result, NULL, CFSTR("service = %@"), prefsPrivate->serviceID);
86 CFStringAppendFormat(result, NULL, CFSTR(", id = %@"), prefsPrivate->prefsID);
87 CFStringAppendFormat(result, NULL, CFSTR("}"));
88
89 return result;
90 }
91
92
93 static void
94 __SCUserPreferencesDeallocate(CFTypeRef cf)
95 {
96 SCUserPreferencesPrivateRef prefsPrivate = (SCUserPreferencesPrivateRef)cf;
97
98 /* release resources */
99
100 CFRelease(prefsPrivate->prefsID);
101 CFRelease(prefsPrivate->serviceID);
102
103 return;
104 }
105
106
107 static Boolean
108 __SCUserPreferencesEqual(CFTypeRef cf1, CFTypeRef cf2)
109 {
110 SCUserPreferencesPrivateRef s1 = (SCUserPreferencesPrivateRef)cf1;
111 SCUserPreferencesPrivateRef s2 = (SCUserPreferencesPrivateRef)cf2;
112
113 if (s1 == s2)
114 return TRUE;
115
116 if (!CFEqual(s1->prefsID, s2->prefsID))
117 return FALSE; // if not the same [unique] prefs identifier
118
119 return TRUE;
120 }
121
122
123 static CFHashCode
124 __SCUserPreferencesHash(CFTypeRef cf)
125 {
126 SCUserPreferencesPrivateRef prefsPrivate = (SCUserPreferencesPrivateRef)cf;
127
128 return CFHash(prefsPrivate->prefsID);
129 }
130
131
132 static void
133 __SCUserPreferencesInitialize(void)
134 {
135 __kSCUserPreferencesTypeID = _CFRuntimeRegisterClass(&__SCUserPreferencesClass);
136 return;
137 }
138
139
140 static SCUserPreferencesPrivateRef
141 __SCUserPreferencesCreatePrivate(CFAllocatorRef allocator,
142 CFStringRef serviceID,
143 CFStringRef prefsID)
144 {
145 SCUserPreferencesPrivateRef prefsPrivate;
146 uint32_t size;
147
148 /* initialize runtime */
149 pthread_once(&initialized, __SCUserPreferencesInitialize);
150
151 /* allocate target */
152 size = sizeof(SCUserPreferencesPrivate) - sizeof(CFRuntimeBase);
153 prefsPrivate = (SCUserPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
154 __kSCUserPreferencesTypeID,
155 size,
156 NULL);
157 if (prefsPrivate == NULL) {
158 return NULL;
159 }
160
161 prefsPrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
162 prefsPrivate->prefsID = CFStringCreateCopy(NULL, prefsID);
163
164 return prefsPrivate;
165 }
166
167
168 static __inline__ CFTypeRef
169 isA_SCUserPreferences(CFTypeRef obj)
170 {
171 return (isA_CFType(obj, SCUserPreferencesGetTypeID()));
172 }
173
174
175 #pragma mark -
176 #pragma mark SCUserPreferences SPIs
177
178
179 #define USER_PREFERENCES_NOTIFICATION "com.apple.networkConnect"
180 #define USER_PREFERENCES_APPLICATION_ID CFSTR("com.apple.networkConnect")
181 #define USER_PREFERENCES_ID CFSTR("UniqueIdentifier")
182 #define USER_PREFERENCES_DEFAULT CFSTR("ConnectByDefault")
183
184
185 #define LOG_CFPREFERENCES_CHANGES
186 #ifdef LOG_CFPREFERENCES_CHANGES
187 #include <fcntl.h>
188 #include <unistd.h>
189 #include <sys/stat.h>
190 #include <sys/time.h>
191 static void
192 logCFPreferencesChange(CFStringRef serviceID, CFArrayRef newPreferences)
193 {
194 CFBooleanRef bVal;
195 char dir[256];
196 CFArrayRef oldPreferences;
197 CFStringRef str;
198 CFStringRef trace;
199 struct tm tm_now;
200 struct timeval tv_now;
201
202 bVal = CFPreferencesCopyAppValue(CFSTR("LOG_SC_CHANGES"), USER_PREFERENCES_APPLICATION_ID);
203 if (bVal != NULL) {
204 if (!isA_CFBoolean(bVal) || !CFBooleanGetValue(bVal)) {
205 // if debugging not enabled
206 CFRelease(bVal);
207 return;
208 }
209 } else {
210 // if debugging not enabled
211 return;
212 }
213
214 (void)gettimeofday(&tv_now, NULL);
215 (void)localtime_r(&tv_now.tv_sec, &tm_now);
216
217 str = CFStringCreateWithFormat(NULL, NULL,
218 CFSTR("/var/tmp/com.apple.networkConnect-%@-%4d%02d%02d.%02d%02d%02d.%03d"),
219 serviceID,
220 tm_now.tm_year + 1900,
221 tm_now.tm_mon + 1,
222 tm_now.tm_mday,
223 tm_now.tm_hour,
224 tm_now.tm_min,
225 tm_now.tm_sec,
226 tv_now.tv_usec / 1000);
227 _SC_cfstring_to_cstring(str, dir, sizeof(dir), kCFStringEncodingUTF8);
228 CFRelease(str);
229
230 SCLog(TRUE, LOG_ERR, CFSTR("CFPreferences being updated, old/new in \"%s\""), dir);
231
232 if (mkdir(dir, 0755) == -1) {
233 SCLog(TRUE, LOG_ERR, CFSTR("logCFPreferencesChange mkdir() failed, error = %s"), SCErrorString(errno));
234 return;
235 }
236
237 trace = _SC_copyBacktrace();
238 if (trace != NULL) {
239 FILE *f;
240 int fd;
241 char path[256];
242
243 strlcpy(path, dir, sizeof(path));
244 strlcat(path, "/backtrace", sizeof(path));
245 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
246 if (fd == -1) {
247 SCLog(TRUE, LOG_ERR, CFSTR("logCFPreferencesChange fopen() failed, error = %s"), SCErrorString(errno));
248 CFRelease(trace);
249 return;
250 }
251 f = fdopen(fd, "w");
252 SCPrint(TRUE, f, CFSTR("%@"), trace);
253 (void) fclose(f);
254 CFRelease(trace);
255 }
256
257 oldPreferences = CFPreferencesCopyAppValue(serviceID, USER_PREFERENCES_APPLICATION_ID);
258 if (oldPreferences != NULL) {
259 int fd;
260 CFDataRef data;
261 char path[256];
262
263 strlcpy(path, dir, sizeof(path));
264 strlcat(path, "/old", sizeof(path));
265 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
266 if (fd == -1) {
267 SCLog(TRUE, LOG_ERR, CFSTR("logCFPreferencesChange fopen() failed, error = %s"), SCErrorString(errno));
268 CFRelease(oldPreferences);
269 return;
270 }
271 data = CFPropertyListCreateXMLData(NULL, oldPreferences);
272 if (data == NULL) {
273 SCLog(TRUE, LOG_ERR, CFSTR("logCFPreferencesChange CFPropertyListCreateXMLData() failed"));
274 close(fd);
275 CFRelease(oldPreferences);
276 return;
277 }
278 (void) write(fd, CFDataGetBytePtr(data), CFDataGetLength(data));
279 (void) close(fd);
280 CFRelease(data);
281 CFRelease(oldPreferences);
282 }
283
284 if (newPreferences != NULL) {
285 int fd;
286 CFDataRef data;
287 char path[256];
288
289 strlcpy(path, dir, sizeof(path));
290 strlcat(path, "/new", sizeof(path));
291 fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
292 if (fd == -1) {
293 SCLog(TRUE, LOG_ERR, CFSTR("logCFPreferencesChange fopen() failed, error = %s"), SCErrorString(errno));
294 return;
295 }
296 data = CFPropertyListCreateXMLData(NULL, newPreferences);
297 if (data == NULL) {
298 SCLog(TRUE, LOG_ERR, CFSTR("logCFPreferencesChange CFPropertyListCreateXMLData() failed"));
299 close(fd);
300 return;
301 }
302 (void) write(fd, CFDataGetBytePtr(data), CFDataGetLength(data));
303 (void) close(fd);
304 CFRelease(data);
305 }
306
307 return;
308 }
309 #endif // LOG_CFPREFERENCES_CHANGES
310
311
312 static CFArrayRef
313 copyCFPreferencesForServiceID(CFStringRef serviceID)
314 {
315 CFArrayRef prefs;
316
317 // fetch "Managed" or "ByHost" user preferences
318 (void) CFPreferencesAppSynchronize(USER_PREFERENCES_APPLICATION_ID);
319 prefs = CFPreferencesCopyAppValue(serviceID,
320 USER_PREFERENCES_APPLICATION_ID);
321
322 if ((prefs != NULL) && !isA_CFArray(prefs)) {
323 CFRelease(prefs);
324 return NULL;
325 }
326
327 return prefs;
328 }
329
330
331 static Boolean
332 setCFPreferencesForServiceID(CFStringRef serviceID, CFArrayRef newPreferences)
333 {
334 Boolean ok;
335
336 if (CFPreferencesAppValueIsForced(serviceID, USER_PREFERENCES_APPLICATION_ID)) {
337 return FALSE;
338 }
339
340 #ifdef LOG_CFPREFERENCES_CHANGES
341 logCFPreferencesChange(serviceID, newPreferences);
342 #endif // LOG_CFPREFERENCES_CHANGES
343
344 CFPreferencesSetValue(serviceID,
345 newPreferences,
346 USER_PREFERENCES_APPLICATION_ID,
347 kCFPreferencesCurrentUser,
348 kCFPreferencesCurrentHost);
349 ok = CFPreferencesSynchronize(USER_PREFERENCES_APPLICATION_ID,
350 kCFPreferencesCurrentUser,
351 kCFPreferencesCurrentHost);
352
353 (void) notify_post(USER_PREFERENCES_NOTIFICATION);
354
355 return ok;
356 }
357
358
359 static void
360 addPreference(CFMutableArrayRef *newPrefs, CFDictionaryRef newDict)
361 {
362 if (*newPrefs == NULL) {
363 *newPrefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
364 }
365 CFArrayAppendValue(*newPrefs, newDict);
366
367 return;
368 }
369
370
371 typedef CFDictionaryRef (*processPreferencesCallout) (CFStringRef serviceID,
372 CFDictionaryRef current,
373 void *context1,
374 void *context2,
375 void *context3);
376
377
378 static Boolean
379 processPreferences(CFStringRef serviceID,
380 processPreferencesCallout callout,
381 void *context1,
382 void *context2,
383 void *context3)
384 {
385 Boolean changed = FALSE;
386 CFIndex i;
387 CFIndex n;
388 CFDictionaryRef newDict = NULL;
389 CFMutableArrayRef newPrefs = NULL;
390 Boolean ok = TRUE;
391 CFArrayRef prefs;
392
393 prefs = copyCFPreferencesForServiceID(serviceID);
394 n = (prefs != NULL) ? CFArrayGetCount(prefs) : 0;
395 for (i = 0; i < n; i++) {
396 CFDictionaryRef dict;
397
398 dict = CFArrayGetValueAtIndex(prefs, i);
399 if (isA_CFDictionary(dict)) {
400 newDict = (*callout)(serviceID, dict, context1, context2, context3);
401 if (newDict == NULL) {
402 // if entry to be removed
403 changed = TRUE;
404 continue;
405 }
406 } else {
407 // if not a CFDictionary, leave as-is
408 newDict = CFRetain(dict);
409 }
410
411 if (!CFEqual(dict, newDict)) {
412 changed = TRUE;
413 }
414
415 addPreference(&newPrefs, newDict);
416 CFRelease(newDict);
417 }
418 if (prefs != NULL) CFRelease(prefs);
419
420 newDict = (*callout)(serviceID, NULL, context1, context2, context3);
421 if (newDict != NULL) {
422 // if new entry
423 changed = TRUE;
424 addPreference(&newPrefs, newDict);
425 CFRelease(newDict);
426 }
427
428 if (changed) {
429 ok = setCFPreferencesForServiceID(serviceID, newPrefs);
430 }
431 if (newPrefs != NULL) CFRelease(newPrefs);
432
433 return ok;
434 }
435
436
437 static __inline__ Boolean
438 isMatchingPrefsID(CFDictionaryRef dict, CFStringRef matchID)
439 {
440 CFStringRef prefsID;
441
442 prefsID = CFDictionaryGetValue(dict, USER_PREFERENCES_ID);
443 if (isA_CFString(prefsID)) {
444 if (CFEqual(prefsID, matchID)) {
445 return TRUE;
446 }
447 }
448
449 return FALSE;
450 }
451
452
453 CFTypeID
454 SCUserPreferencesGetTypeID(void)
455 {
456 pthread_once(&initialized, __SCUserPreferencesInitialize); /* initialize runtime */
457 return __kSCUserPreferencesTypeID;
458 }
459
460
461 CFStringRef
462 SCUserPreferencesGetUniqueID(SCUserPreferencesRef userPreferences)
463 {
464 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
465
466 if (!isA_SCUserPreferences(userPreferences)) {
467 _SCErrorSet(kSCStatusInvalidArgument);
468 return FALSE;
469 }
470
471 return userPrivate->prefsID;
472 }
473
474
475 Boolean
476 SCUserPreferencesIsForced(SCUserPreferencesRef userPreferences)
477 {
478 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
479
480 if (!isA_SCUserPreferences(userPreferences)) {
481 _SCErrorSet(kSCStatusInvalidArgument);
482 return FALSE;
483 }
484
485 return CFPreferencesAppValueIsForced(userPrivate->serviceID, USER_PREFERENCES_APPLICATION_ID);
486 }
487
488
489 static CFDictionaryRef
490 removeCallout(CFStringRef serviceID,
491 CFDictionaryRef current,
492 void *context1,
493 void *context2,
494 void *context3)
495 {
496 CFStringRef matchID = (CFStringRef)context1;
497
498 if (current == NULL) {
499 // we have nothing to "add"
500 return NULL;
501 }
502
503 if (isMatchingPrefsID(current, matchID)) {
504 // if we match, don't add (i.e. remove)
505 return NULL;
506 }
507
508 return CFRetain(current);
509 }
510
511
512 Boolean
513 SCUserPreferencesRemove(SCUserPreferencesRef userPreferences)
514 {
515 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
516
517 if (!isA_SCUserPreferences(userPreferences)) {
518 _SCErrorSet(kSCStatusInvalidArgument);
519 return FALSE;
520 }
521
522 return processPreferences(userPrivate->serviceID,
523 removeCallout,
524 (void *)userPrivate->prefsID,
525 NULL,
526 NULL);
527 }
528
529
530 static CFDictionaryRef
531 setCurrentCallout(CFStringRef serviceID,
532 CFDictionaryRef current,
533 void *context1,
534 void *context2,
535 void *context3)
536 {
537 CFStringRef matchID = (CFStringRef)context1;
538 CFMutableDictionaryRef newDict;
539
540 if (current == NULL) {
541 // we have nothing to "add"
542 return NULL;
543 }
544
545 newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
546
547 // remove "default" flag
548 CFDictionaryRemoveValue(newDict, USER_PREFERENCES_DEFAULT);
549
550 if (isMatchingPrefsID(current, matchID)) {
551 // if we match, set "default" flag
552 CFDictionarySetValue(newDict, USER_PREFERENCES_DEFAULT, kCFBooleanTrue);
553 }
554
555 return newDict;
556 }
557
558
559 Boolean
560 SCUserPreferencesSetCurrent(SCUserPreferencesRef userPreferences)
561 {
562 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
563
564 if (!isA_SCUserPreferences(userPreferences)) {
565 _SCErrorSet(kSCStatusInvalidArgument);
566 return FALSE;
567 }
568
569 return processPreferences(userPrivate->serviceID,
570 setCurrentCallout,
571 (void *)userPrivate->prefsID,
572 NULL,
573 NULL);
574 }
575
576
577 static CFDictionaryRef
578 copyNameCallout(CFStringRef serviceID,
579 CFDictionaryRef current,
580 void *context1,
581 void *context2,
582 void *context3)
583 {
584 CFStringRef matchID = (CFStringRef)context1;
585 CFStringRef *name = (CFStringRef *)context3;
586
587 if (current == NULL) {
588 // we have nothing to "add"
589 return NULL;
590 }
591
592 if (isMatchingPrefsID(current, matchID)) {
593 *name = CFDictionaryGetValue(current, kSCPropUserDefinedName);
594
595 // for backwards compatibility, we also check for the name in the PPP entity
596 if (*name == NULL) {
597 CFDictionaryRef ppp;
598
599 ppp = CFDictionaryGetValue(current, kSCEntNetPPP);
600 if (isA_CFDictionary(ppp)) {
601 *name = CFDictionaryGetValue(ppp, kSCPropUserDefinedName);
602 }
603 }
604
605 *name = isA_CFString(*name);
606 if (*name != NULL) {
607 CFRetain(*name);
608 }
609 }
610
611 return CFRetain(current);
612 }
613
614
615 CFStringRef
616 SCUserPreferencesCopyName(SCUserPreferencesRef userPreferences)
617 {
618 CFStringRef name = NULL;
619 Boolean ok;
620 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
621
622 if (!isA_SCUserPreferences(userPreferences)) {
623 _SCErrorSet(kSCStatusInvalidArgument);
624 return FALSE;
625 }
626
627 // find SCUserPreferences and copy name
628 ok = processPreferences(userPrivate->serviceID,
629 copyNameCallout,
630 (void *)userPrivate->prefsID,
631 NULL,
632 (void *)&name);
633 if (!ok) {
634 if (name != NULL) {
635 CFRelease(name);
636 name = NULL;
637 }
638 }
639
640 return name;
641 }
642
643
644 static CFDictionaryRef
645 setNameCallout(CFStringRef serviceID,
646 CFDictionaryRef current,
647 void *context1,
648 void *context2,
649 void *context3)
650 {
651 CFStringRef matchID = (CFStringRef)context1;
652 CFMutableDictionaryRef newDict;
653 CFStringRef newName = (CFStringRef)context2;
654
655 if (current == NULL) {
656 // we have nothing to "add"
657 return NULL;
658 }
659
660 newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
661
662 if (isMatchingPrefsID(current, matchID)) {
663 CFDictionaryRef pppEntity;
664
665 // set the name
666 if (newName != NULL) {
667 CFDictionarySetValue(newDict, kSCPropUserDefinedName, newName);
668 } else {
669 CFDictionaryRemoveValue(newDict, kSCPropUserDefinedName);
670 }
671
672 // for backwards compatibility, we also set the name in the PPP entity
673 pppEntity = CFDictionaryGetValue(newDict, kSCEntNetPPP);
674 if (isA_CFDictionary(pppEntity)) {
675 CFMutableDictionaryRef newPPPEntity;
676
677 newPPPEntity = CFDictionaryCreateMutableCopy(NULL, 0, pppEntity);
678 if (newName != NULL) {
679 CFDictionarySetValue(newPPPEntity, kSCPropUserDefinedName, newName);
680 } else {
681 CFDictionaryRemoveValue(newPPPEntity, kSCPropUserDefinedName);
682 }
683 CFDictionarySetValue(newDict, kSCEntNetPPP, newPPPEntity);
684 CFRelease(newPPPEntity);
685 }
686 }
687
688 return newDict;
689 }
690
691
692 Boolean
693 SCUserPreferencesSetName(SCUserPreferencesRef userPreferences, CFStringRef newName)
694 {
695 Boolean ok;
696 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
697
698 if (!isA_SCUserPreferences(userPreferences)) {
699 _SCErrorSet(kSCStatusInvalidArgument);
700 return FALSE;
701 }
702
703 if ((newName != NULL) && !isA_CFString(newName)) {
704 _SCErrorSet(kSCStatusInvalidArgument);
705 return FALSE;
706 }
707
708 // find SCUserPreferences and set name
709 ok = processPreferences(userPrivate->serviceID,
710 setNameCallout,
711 (void *)userPrivate->prefsID,
712 (void *)newName,
713 NULL);
714
715 return ok;
716 }
717
718
719 static CFDictionaryRef
720 copyInterfaceConfigurationCallout(CFStringRef serviceID,
721 CFDictionaryRef current,
722 void *context1,
723 void *context2,
724 void *context3)
725 {
726 CFDictionaryRef *dict = (CFDictionaryRef *)context3;
727 CFStringRef interfaceType = (CFStringRef)context2;
728 CFStringRef matchID = (CFStringRef)context1;
729
730 if (current == NULL) {
731 // we have nothing to "add"
732 return NULL;
733 }
734
735 if (isMatchingPrefsID(current, matchID)) {
736 *dict = CFDictionaryGetValue(current, interfaceType);
737 *dict = isA_CFDictionary(*dict);
738 if (*dict != NULL) {
739 CFRetain(*dict);
740 }
741 }
742
743 return CFRetain(current);
744 }
745
746
747 CFDictionaryRef
748 SCUserPreferencesCopyInterfaceConfiguration(SCUserPreferencesRef userPreferences,
749 SCNetworkInterfaceRef interface)
750 {
751 CFStringRef defaultType;
752 CFDictionaryRef entity = NULL;
753 Boolean ok;
754 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
755
756 if (!isA_SCUserPreferences(userPreferences)) {
757 _SCErrorSet(kSCStatusInvalidArgument);
758 return NULL;
759 }
760
761 if (!isA_SCNetworkInterface(interface)) {
762 _SCErrorSet(kSCStatusInvalidArgument);
763 return NULL;
764 }
765
766 // get InterfaceType
767 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
768 if (defaultType == NULL) {
769 _SCErrorSet(kSCStatusInvalidArgument);
770 return NULL;
771 }
772
773 // find SCUserPreferences and copy interface entity
774 ok = processPreferences(userPrivate->serviceID,
775 copyInterfaceConfigurationCallout,
776 (void *)userPrivate->prefsID,
777 (void *)defaultType,
778 (void *)&entity);
779 if (!ok) {
780 if (entity != NULL) {
781 CFRelease(entity);
782 entity = NULL;
783 }
784 }
785
786 return entity;
787 }
788
789
790 static CFDictionaryRef
791 setInterfaceConfigurationCallout(CFStringRef serviceID,
792 CFDictionaryRef current,
793 void *context1,
794 void *context2,
795 void *context3)
796 {
797 CFStringRef interfaceType = (CFStringRef)context2;
798 CFStringRef matchID = (CFStringRef)context1;
799 CFMutableDictionaryRef newDict;
800 CFDictionaryRef newOptions = (CFDictionaryRef)context3;
801
802 if (current == NULL) {
803 // we have nothing to "add"
804 return NULL;
805 }
806
807 newDict = CFDictionaryCreateMutableCopy(NULL, 0, current);
808
809 if (isMatchingPrefsID(current, matchID)) {
810 if (newOptions != NULL) {
811 CFDictionarySetValue(newDict, interfaceType, newOptions);
812
813 // for backwards compatibility, we want to ensure that
814 // the name is set in both the top level and in the PPP
815 // entity.
816 if (CFEqual(interfaceType, kSCEntNetPPP)) {
817 CFStringRef name;
818
819 name = CFDictionaryGetValue(newOptions, kSCPropUserDefinedName);
820 if (name != NULL) {
821 // if name was passed in newOptions, push up
822 CFDictionarySetValue(newDict, kSCPropUserDefinedName, name);
823 } else {
824 name = CFDictionaryGetValue(newDict, kSCPropUserDefinedName);
825 if (name != NULL) {
826 CFMutableDictionaryRef newPPPEntity;
827
828 // if name in parent, push into entity
829 newPPPEntity = CFDictionaryCreateMutableCopy(NULL, 0, newOptions);
830 CFDictionarySetValue(newPPPEntity, kSCPropUserDefinedName, name);
831 CFDictionarySetValue(newDict, interfaceType, newPPPEntity);
832 CFRelease(newPPPEntity);
833 }
834 }
835 }
836 } else {
837 CFDictionaryRemoveValue(newDict, interfaceType);
838 }
839 }
840
841 return newDict;
842 }
843
844
845 Boolean
846 SCUserPreferencesSetInterfaceConfiguration(SCUserPreferencesRef userPreferences,
847 SCNetworkInterfaceRef interface,
848 CFDictionaryRef newOptions)
849 {
850 CFStringRef defaultType;
851 Boolean ok;
852 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
853
854 if (!isA_SCUserPreferences(userPreferences)) {
855 _SCErrorSet(kSCStatusInvalidArgument);
856 return FALSE;
857 }
858
859 if (!isA_SCNetworkInterface(interface)) {
860 _SCErrorSet(kSCStatusInvalidArgument);
861 return FALSE;
862 }
863
864 // get InterfaceType
865 defaultType = __SCNetworkInterfaceGetDefaultConfigurationType(interface);
866 if (defaultType == NULL) {
867 _SCErrorSet(kSCStatusInvalidArgument);
868 return FALSE;
869 }
870
871 // set new interface entity for SCUserPreferences
872 ok = processPreferences(userPrivate->serviceID,
873 setInterfaceConfigurationCallout,
874 (void *)userPrivate->prefsID,
875 (void *)defaultType,
876 (void *)newOptions);
877
878 return ok;
879 }
880
881
882 CFDictionaryRef
883 SCUserPreferencesCopyExtendedInterfaceConfiguration(SCUserPreferencesRef userPreferences,
884 SCNetworkInterfaceRef interface,
885 CFStringRef extendedType)
886 {
887 CFDictionaryRef entity = NULL;
888 Boolean ok;
889 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
890
891 if (!isA_SCUserPreferences(userPreferences)) {
892 _SCErrorSet(kSCStatusInvalidArgument);
893 return NULL;
894 }
895
896 if (!isA_SCNetworkInterface(interface)) {
897 _SCErrorSet(kSCStatusInvalidArgument);
898 return NULL;
899 }
900
901 if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, FALSE)) {
902 _SCErrorSet(kSCStatusInvalidArgument);
903 return NULL;
904 }
905
906 // find SCUserPreferences and copy interface entity
907 ok = processPreferences(userPrivate->serviceID,
908 copyInterfaceConfigurationCallout,
909 (void *)userPrivate->prefsID,
910 (void *)extendedType,
911 (void *)&entity);
912 if (!ok) {
913 if (entity != NULL) {
914 CFRelease(entity);
915 entity = NULL;
916 }
917 }
918
919 return entity;
920 }
921
922
923 Boolean
924 SCUserPreferencesSetExtendedInterfaceConfiguration(SCUserPreferencesRef userPreferences,
925 SCNetworkInterfaceRef interface,
926 CFStringRef extendedType,
927 CFDictionaryRef newOptions)
928 {
929 Boolean ok;
930 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
931
932 if (!isA_SCUserPreferences(userPreferences)) {
933 _SCErrorSet(kSCStatusInvalidArgument);
934 return FALSE;
935 }
936
937 if (!isA_SCNetworkInterface(interface)) {
938 _SCErrorSet(kSCStatusInvalidArgument);
939 return FALSE;
940 }
941
942 if (!__SCNetworkInterfaceIsValidExtendedConfigurationType(interface, extendedType, FALSE)) {
943 _SCErrorSet(kSCStatusInvalidArgument);
944 return FALSE;
945 }
946
947 // set new interface entity for SCUserPreferences
948 ok = processPreferences(userPrivate->serviceID,
949 setInterfaceConfigurationCallout,
950 (void *)userPrivate->prefsID,
951 (void *)extendedType,
952 (void *)newOptions);
953
954 return ok;
955 }
956
957
958 #pragma mark -
959 #pragma mark SCNetworkConnection + SCUserPreferences SPIs
960
961
962 static CFDictionaryRef
963 copyAllCallout(CFStringRef serviceID,
964 CFDictionaryRef current,
965 void *context1,
966 void *context2,
967 void *context3)
968 {
969 CFMutableArrayRef *prefs = (CFMutableArrayRef *)context3;
970 CFStringRef prefsID;
971 SCUserPreferencesPrivateRef userPrivate;
972
973 if (current == NULL) {
974 // we have nothing to "add"
975 return NULL;
976 }
977
978 prefsID = CFDictionaryGetValue(current, USER_PREFERENCES_ID);
979 if (!isA_CFString(prefsID)) {
980 // if no unique ID
981 goto done;
982 }
983
984 userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, prefsID);
985 if (userPrivate != NULL) {
986 if (*prefs == NULL) {
987 *prefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
988 }
989 CFArrayAppendValue(*prefs, (SCUserPreferencesRef)userPrivate);
990 CFRelease(userPrivate);
991 }
992
993 done :
994
995 return CFRetain(current);
996 }
997
998
999 CFArrayRef /* of SCUserPreferencesRef's */
1000 SCNetworkConnectionCopyAllUserPreferences(SCNetworkConnectionRef connection)
1001 {
1002 Boolean ok;
1003 CFMutableArrayRef prefs = NULL;
1004 CFStringRef serviceID;
1005
1006 // get serviceID
1007 serviceID = SCNetworkConnectionCopyServiceID(connection);
1008
1009 // collect SCUserPreferences
1010 ok = processPreferences(serviceID,
1011 copyAllCallout,
1012 NULL,
1013 NULL,
1014 (void *)&prefs);
1015 if (!ok) {
1016 if (prefs != NULL) {
1017 CFRelease(prefs);
1018 prefs = NULL;
1019 }
1020 }
1021
1022 CFRelease(serviceID);
1023 return prefs;
1024 }
1025
1026
1027 static CFDictionaryRef
1028 copyCurrentCallout(CFStringRef serviceID,
1029 CFDictionaryRef current,
1030 void *context1,
1031 void *context2,
1032 void *context3)
1033 {
1034 CFBooleanRef isDefault;
1035 CFStringRef prefsID;
1036 SCUserPreferencesPrivateRef *userPrivate = (SCUserPreferencesPrivateRef *)context3;
1037
1038 if (current == NULL) {
1039 // we have nothing to "add"
1040 return NULL;
1041 }
1042
1043 prefsID = CFDictionaryGetValue(current, USER_PREFERENCES_ID);
1044 if (!isA_CFString(prefsID)) {
1045 // if no unique ID
1046 goto done;
1047 }
1048
1049 isDefault = CFDictionaryGetValue(current, USER_PREFERENCES_DEFAULT);
1050 if (!isA_CFBoolean(isDefault) || !CFBooleanGetValue(isDefault)) {
1051 // if not the default configuration
1052 goto done;
1053 }
1054
1055 *userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, prefsID);
1056
1057 done :
1058
1059 return CFRetain(current);
1060 }
1061
1062
1063 SCUserPreferencesRef
1064 SCNetworkConnectionCopyCurrentUserPreferences(SCNetworkConnectionRef connection)
1065 {
1066 SCUserPreferencesRef current = NULL;
1067 Boolean ok;
1068 CFStringRef serviceID;
1069
1070 // get serviceID
1071 serviceID = SCNetworkConnectionCopyServiceID(connection);
1072
1073 // collect SCUserPreferences
1074 ok = processPreferences(serviceID,
1075 copyCurrentCallout,
1076 NULL,
1077 NULL,
1078 (void *)&current);
1079 if (!ok) {
1080 if (current != NULL) {
1081 CFRelease(current);
1082 current = NULL;
1083 }
1084 }
1085
1086 CFRelease(serviceID);
1087 return current;
1088 }
1089
1090
1091 static CFDictionaryRef
1092 createCallout(CFStringRef serviceID,
1093 CFDictionaryRef current,
1094 void *context1,
1095 void *context2,
1096 void *context3)
1097 {
1098 CFMutableDictionaryRef newDict;
1099 CFStringRef newPrefsID = (CFStringRef)context1;
1100
1101 if (current != NULL) {
1102 // don't change existing entries
1103 return CFRetain(current);
1104 }
1105
1106 newDict = CFDictionaryCreateMutable(NULL,
1107 0,
1108 &kCFTypeDictionaryKeyCallBacks,
1109 &kCFTypeDictionaryValueCallBacks);
1110 CFDictionarySetValue(newDict, USER_PREFERENCES_ID, newPrefsID);
1111 return newDict;
1112 }
1113
1114
1115 SCUserPreferencesRef
1116 SCNetworkConnectionCreateUserPreferences(SCNetworkConnectionRef connection)
1117 {
1118 CFStringRef newPrefsID;
1119 CFStringRef serviceID;
1120 SCUserPreferencesPrivateRef userPrivate;
1121 CFUUIDRef uuid;
1122
1123 // get serviceID
1124 serviceID = SCNetworkConnectionCopyServiceID(connection);
1125
1126 // allocate a new user preferences ID
1127 uuid = CFUUIDCreate(NULL);
1128 newPrefsID = CFUUIDCreateString(NULL, uuid);
1129 CFRelease(uuid);
1130
1131 userPrivate = __SCUserPreferencesCreatePrivate(NULL, serviceID, newPrefsID);
1132 if (userPrivate != NULL) {
1133 (void) processPreferences(serviceID,
1134 createCallout,
1135 (void *)newPrefsID,
1136 NULL,
1137 NULL);
1138 }
1139
1140 CFRelease(newPrefsID);
1141 CFRelease(serviceID);
1142 return (SCUserPreferencesRef)userPrivate;
1143 }
1144
1145
1146 static void
1147 update_PPP_entity(SCUserPreferencesRef userPreferences, CFDictionaryRef *userOptions)
1148 {
1149 CFStringRef encryption;
1150 CFDictionaryRef entity;
1151 CFStringRef keychainID;
1152
1153 entity = CFDictionaryGetValue(*userOptions, kSCEntNetPPP);
1154 if (!isA_CFDictionary(entity)) {
1155 return;
1156 }
1157
1158 encryption = CFDictionaryGetValue(entity, kSCPropNetPPPAuthPasswordEncryption);
1159 if (encryption == NULL) {
1160 // provide default encryption method
1161 encryption = kSCValNetPPPAuthPasswordEncryptionKeychain;
1162 }
1163
1164 if (!isA_CFString(encryption) ||
1165 !CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
1166 return;
1167 }
1168
1169 keychainID = CFDictionaryGetValue(entity, kSCPropNetPPPAuthPassword);
1170 if (isA_CFString(keychainID)) {
1171 // if password is keychain ID
1172 } else if (isA_CFData(keychainID) &&
1173 ((CFDataGetLength((CFDataRef)keychainID) % sizeof(UniChar)) == 0)) {
1174 // if inline password
1175 return;
1176 } else {
1177 keychainID = SCUserPreferencesGetUniqueID(userPreferences);
1178 }
1179
1180 if (_SCSecKeychainPasswordItemExists(NULL, keychainID)) {
1181 CFMutableDictionaryRef new_entity;
1182 CFMutableDictionaryRef new_options;
1183
1184 // access PPP password from system keychain
1185 new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1186
1187 CFDictionarySetValue(new_entity,
1188 kSCPropNetPPPAuthPassword,
1189 keychainID);
1190 CFDictionarySetValue(new_entity,
1191 kSCPropNetPPPAuthPasswordEncryption,
1192 kSCValNetPPPAuthPasswordEncryptionKeychain);
1193
1194 new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
1195 CFDictionarySetValue(new_options, kSCEntNetPPP, new_entity);
1196 CFRelease(new_entity);
1197
1198 CFRelease(*userOptions);
1199 *userOptions = new_options;
1200 }
1201
1202 return;
1203 }
1204
1205
1206 static void
1207 update_IPSec_entity(SCUserPreferencesRef userPreferences, CFDictionaryRef *userOptions)
1208 {
1209 CFStringRef encryption;
1210 CFDictionaryRef entity;
1211 SecKeychainRef keychain = NULL;
1212 CFStringRef keychainID;
1213 CFStringRef method;
1214 CFDataRef sharedSecret;
1215
1216 entity = CFDictionaryGetValue(*userOptions, kSCEntNetIPSec);
1217 if (!isA_CFDictionary(entity)) {
1218 return;
1219 }
1220
1221 method = CFDictionaryGetValue(entity, kSCPropNetIPSecAuthenticationMethod);
1222 if (!isA_CFString(method) ||
1223 !CFEqual(method, kSCValNetIPSecAuthenticationMethodSharedSecret)) {
1224 return;
1225 }
1226
1227 encryption = CFDictionaryGetValue(entity, kSCPropNetIPSecSharedSecretEncryption);
1228 if (encryption == NULL) {
1229 // provide default encryption method
1230 encryption = kSCValNetIPSecSharedSecretEncryptionKeychain;
1231 }
1232
1233 if (!isA_CFString(encryption) ||
1234 !CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
1235 return;
1236 }
1237
1238 keychainID = CFDictionaryGetValue(entity, kSCPropNetIPSecSharedSecret);
1239 if (isA_CFString(keychainID)) {
1240 // if shared secret is keychain ID
1241 CFRetain(keychainID);
1242 } else if (isA_CFData(keychainID) &&
1243 ((CFDataGetLength((CFDataRef)keychainID) % sizeof(UniChar)) == 0)) {
1244 // if inline shared secret
1245 return;
1246 } else {
1247 CFStringRef unique_id;
1248
1249 unique_id = SCUserPreferencesGetUniqueID(userPreferences);
1250 keychainID = (CFStringRef)CFStringCreateMutableCopy(NULL, 0, unique_id);
1251 CFStringAppend((CFMutableStringRef)keychainID, CFSTR(".SS"));
1252 }
1253
1254 sharedSecret = _SCSecKeychainPasswordItemCopy(NULL, keychainID);
1255 if (sharedSecret != NULL) {
1256 CFMutableDictionaryRef new_entity;
1257 CFMutableDictionaryRef new_options;
1258 CFStringRef password;
1259
1260 // pass SharedSecret from user keychain
1261 new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1262
1263 password = CFStringCreateWithBytes(NULL,
1264 CFDataGetBytePtr(sharedSecret),
1265 CFDataGetLength(sharedSecret),
1266 kCFStringEncodingUTF8,
1267 FALSE);
1268 CFRelease(sharedSecret);
1269 CFDictionarySetValue(new_entity,
1270 kSCPropNetIPSecSharedSecret,
1271 password);
1272 CFRelease(password);
1273 CFDictionaryRemoveValue(new_entity,
1274 kSCPropNetIPSecSharedSecretEncryption);
1275
1276 new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
1277 CFDictionarySetValue(new_options, kSCEntNetIPSec, new_entity);
1278 CFRelease(new_entity);
1279
1280 CFRelease(*userOptions);
1281 *userOptions = new_options;
1282 goto done;
1283 }
1284
1285 keychain = _SCSecKeychainCopySystemKeychain();
1286 if (keychain == NULL) {
1287 goto done;
1288 }
1289
1290 if (_SCSecKeychainPasswordItemExists(keychain, keychainID)) {
1291 CFMutableDictionaryRef new_entity;
1292 CFMutableDictionaryRef new_options;
1293
1294 // access SharedSecret from system keychain
1295 new_entity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1296
1297 CFDictionarySetValue(new_entity,
1298 kSCPropNetIPSecSharedSecret,
1299 keychainID);
1300 CFDictionarySetValue(new_entity,
1301 kSCPropNetIPSecSharedSecretEncryption,
1302 kSCValNetIPSecSharedSecretEncryptionKeychain);
1303
1304 new_options = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
1305 CFDictionarySetValue(new_options, kSCEntNetIPSec, new_entity);
1306 CFRelease(new_entity);
1307
1308 CFRelease(*userOptions);
1309 *userOptions = new_options;
1310 }
1311
1312 done :
1313
1314 if (keychain != NULL) CFRelease(keychain);
1315 CFRelease(keychainID);
1316 return;
1317 }
1318
1319
1320 static CFDictionaryRef
1321 copyOptionsCallout(CFStringRef serviceID,
1322 CFDictionaryRef current,
1323 void *context1,
1324 void *context2,
1325 void *context3)
1326 {
1327 CFStringRef matchID = (CFStringRef)context1;
1328 CFMutableDictionaryRef *userOptions = (CFMutableDictionaryRef *)context3;
1329
1330 if (current == NULL) {
1331 // we have nothing to "add"
1332 return NULL;
1333 }
1334
1335 if (isMatchingPrefsID(current, matchID)) {
1336 // if we match, return options dictionary
1337 if (*userOptions != NULL) CFRelease(*userOptions);
1338 *userOptions = CFDictionaryCreateMutableCopy(NULL, 0, current);
1339 CFDictionaryRemoveValue(*userOptions, USER_PREFERENCES_ID);
1340 CFDictionaryRemoveValue(*userOptions, USER_PREFERENCES_DEFAULT);
1341 }
1342
1343 return CFRetain(current);
1344 }
1345
1346
1347 Boolean
1348 SCNetworkConnectionStartWithUserPreferences(SCNetworkConnectionRef connection,
1349 SCUserPreferencesRef userPreferences,
1350 Boolean linger)
1351 {
1352 Boolean ok;
1353 CFDictionaryRef userOptions = NULL;
1354 SCUserPreferencesPrivateRef userPrivate = (SCUserPreferencesPrivateRef)userPreferences;
1355
1356 if (!isA_SCUserPreferences(userPreferences)) {
1357 _SCErrorSet(kSCStatusInvalidArgument);
1358 return FALSE;
1359 }
1360
1361 (void) processPreferences(userPrivate->serviceID,
1362 copyOptionsCallout,
1363 (void *)userPrivate->prefsID,
1364 NULL,
1365 &userOptions);
1366
1367 /*
1368 * For some legacy preferences, some of the user options
1369 * were missing yet handled by the APIs. Make sure that
1370 * everything still works!
1371 */
1372 if (userOptions != NULL) {
1373 update_PPP_entity (userPreferences, &userOptions);
1374 update_IPSec_entity(userPreferences, &userOptions);
1375 }
1376
1377 ok = SCNetworkConnectionStart(connection, userOptions, linger);
1378
1379 if (userOptions != NULL) {
1380 CFRelease(userOptions);
1381 }
1382
1383 return ok;
1384 }
1385
1386
1387 #pragma mark -
1388 #pragma mark SCUserPreferences + SCNetworkInterface Password SPIs
1389
1390
1391 static CFStringRef
1392 getUserPasswordID(CFDictionaryRef config, SCUserPreferencesRef userPreferences)
1393 {
1394 CFStringRef unique_id = NULL;
1395
1396 if (config != NULL) {
1397 CFStringRef encryption;
1398
1399 encryption = CFDictionaryGetValue(config, kSCPropNetPPPAuthPasswordEncryption);
1400 if (isA_CFString(encryption) &&
1401 CFEqual(encryption, kSCValNetPPPAuthPasswordEncryptionKeychain)) {
1402 unique_id = CFDictionaryGetValue(config, kSCPropNetPPPAuthPassword);
1403 }
1404 }
1405 if (unique_id == NULL) {
1406 unique_id = SCUserPreferencesGetUniqueID(userPreferences);
1407 }
1408
1409 return unique_id;
1410 }
1411
1412
1413 static CFStringRef
1414 copyUserSharedSecretID(CFDictionaryRef config, SCUserPreferencesRef userPreferences)
1415 {
1416 CFMutableStringRef sharedSecret = NULL;
1417
1418 if (config != NULL) {
1419 CFStringRef encryption;
1420
1421 encryption = CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecretEncryption);
1422 if (isA_CFString(encryption) &&
1423 CFEqual(encryption, kSCValNetIPSecSharedSecretEncryptionKeychain)) {
1424 sharedSecret = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecSharedSecret);
1425 if (sharedSecret != NULL) {
1426 CFRetain(sharedSecret);
1427 }
1428 }
1429 }
1430
1431 if (sharedSecret == NULL) {
1432 CFStringRef unique_id;
1433
1434 unique_id = getUserPasswordID(config, userPreferences);
1435 sharedSecret = CFStringCreateMutableCopy(NULL, 0, unique_id);
1436 CFStringAppend(sharedSecret, CFSTR(".SS"));
1437 }
1438
1439 return sharedSecret;
1440 }
1441
1442
1443 static CFStringRef
1444 copyUserXAuthID(CFDictionaryRef config, SCUserPreferencesRef userPreferences)
1445 {
1446 CFMutableStringRef xauth_id = NULL;
1447
1448 if (config != NULL) {
1449 CFStringRef encryption;
1450
1451 encryption = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPasswordEncryption);
1452 if (isA_CFString(encryption) &&
1453 CFEqual(encryption, kSCValNetIPSecXAuthPasswordEncryptionKeychain)) {
1454 xauth_id = (CFMutableStringRef)CFDictionaryGetValue(config, kSCPropNetIPSecXAuthPassword);
1455 if (xauth_id != NULL) {
1456 CFRetain(xauth_id);
1457 }
1458 }
1459 }
1460
1461 if (xauth_id == NULL) {
1462 CFStringRef unique_id;
1463
1464 unique_id = getUserPasswordID(config, userPreferences);
1465 xauth_id = CFStringCreateMutableCopy(NULL, 0, unique_id);
1466 CFStringAppend(xauth_id, CFSTR(".XAUTH"));
1467 }
1468
1469 return xauth_id;
1470 }
1471
1472
1473 static Boolean
1474 checkUserPreferencesPassword(SCUserPreferencesRef userPreferences,
1475 SCNetworkInterfaceRef interface,
1476 SCNetworkInterfacePasswordType passwordType)
1477 {
1478 if (!isA_SCUserPreferences(userPreferences)) {
1479 _SCErrorSet(kSCStatusInvalidArgument);
1480 return FALSE;
1481 }
1482
1483 if (!isA_SCNetworkInterface(interface)) {
1484 _SCErrorSet(kSCStatusInvalidArgument);
1485 return FALSE;
1486 }
1487
1488 switch (passwordType) {
1489 case kSCNetworkInterfacePasswordTypePPP : {
1490 CFStringRef interfaceType;
1491
1492 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1493 if (!CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
1494 _SCErrorSet(kSCStatusInvalidArgument);
1495 return FALSE;
1496 }
1497 break;
1498 }
1499
1500 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
1501 CFStringRef interfaceType;
1502
1503 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1504 if (!CFEqual(interfaceType, kSCNetworkInterfaceTypePPP)) {
1505 _SCErrorSet(kSCStatusInvalidArgument);
1506 return FALSE;
1507 }
1508
1509 interface = SCNetworkInterfaceGetInterface(interface);
1510 if (interface == NULL) {
1511 _SCErrorSet(kSCStatusInvalidArgument);
1512 return FALSE;
1513 }
1514
1515 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1516 if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeL2TP)) {
1517 _SCErrorSet(kSCStatusInvalidArgument);
1518 return FALSE;
1519 }
1520 break;
1521 }
1522
1523 case kSCNetworkInterfacePasswordTypeEAPOL : {
1524 _SCErrorSet(kSCStatusInvalidArgument);
1525 return FALSE;
1526 }
1527
1528 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
1529 CFStringRef interfaceType;
1530
1531 interfaceType = SCNetworkInterfaceGetInterfaceType(interface);
1532 if (!CFEqual(interfaceType, kSCNetworkInterfaceTypeIPSec)) {
1533 _SCErrorSet(kSCStatusInvalidArgument);
1534 return FALSE;
1535 }
1536 break;
1537 }
1538
1539 default :
1540 break;
1541 }
1542
1543 return TRUE;
1544 }
1545
1546
1547 Boolean
1548 SCUserPreferencesCheckInterfacePassword(SCUserPreferencesRef userPreferences,
1549 SCNetworkInterfaceRef interface,
1550 SCNetworkInterfacePasswordType passwordType)
1551 {
1552 Boolean exists = FALSE;
1553
1554 if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
1555 return FALSE;
1556 }
1557
1558 switch (passwordType) {
1559 case kSCNetworkInterfacePasswordTypePPP : {
1560 CFDictionaryRef config;
1561 CFStringRef unique_id;
1562
1563 // get configuration
1564 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1565
1566 // get userPreferences ID
1567 unique_id = getUserPasswordID(config, userPreferences);
1568
1569 // check
1570 exists = __extract_password(NULL,
1571 config,
1572 kSCPropNetPPPAuthPassword,
1573 kSCPropNetPPPAuthPasswordEncryption,
1574 kSCValNetPPPAuthPasswordEncryptionKeychain,
1575 unique_id,
1576 NULL);
1577
1578 if (config != NULL) CFRelease(config);
1579 break;
1580 }
1581
1582 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
1583 CFDictionaryRef config;
1584 CFStringRef shared_id;
1585
1586 // get configuration
1587 config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
1588 interface,
1589 kSCEntNetIPSec);
1590
1591 // get sharedSecret ID
1592 shared_id = copyUserSharedSecretID(config, userPreferences);
1593
1594 // check
1595 exists = __extract_password(NULL,
1596 config,
1597 kSCPropNetIPSecSharedSecret,
1598 kSCPropNetIPSecSharedSecretEncryption,
1599 kSCValNetIPSecSharedSecretEncryptionKeychain,
1600 shared_id,
1601 NULL);
1602
1603 if (config != NULL) CFRelease(config);
1604 CFRelease(shared_id);
1605 break;
1606 }
1607
1608 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
1609 CFDictionaryRef config;
1610 CFStringRef xauth_id;
1611
1612 // get configuration
1613 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1614
1615 // get XAuth ID
1616 xauth_id = copyUserXAuthID(config, userPreferences);
1617
1618 // check
1619 exists = __extract_password(NULL,
1620 config,
1621 kSCPropNetIPSecXAuthPassword,
1622 kSCPropNetIPSecXAuthPasswordEncryption,
1623 kSCValNetIPSecXAuthPasswordEncryptionKeychain,
1624 xauth_id,
1625 NULL);
1626
1627 if (config != NULL) CFRelease(config);
1628 CFRelease(xauth_id);
1629 break;
1630 }
1631
1632 default :
1633 _SCErrorSet(kSCStatusInvalidArgument);
1634 return FALSE;
1635 }
1636
1637 return exists;
1638 }
1639
1640
1641 CFDataRef
1642 SCUserPreferencesCopyInterfacePassword(SCUserPreferencesRef userPreferences,
1643 SCNetworkInterfaceRef interface,
1644 SCNetworkInterfacePasswordType passwordType)
1645 {
1646 CFDataRef password = NULL;
1647
1648 if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
1649 return FALSE;
1650 }
1651
1652 switch (passwordType) {
1653 case kSCNetworkInterfacePasswordTypePPP : {
1654 CFDictionaryRef config;
1655 CFStringRef unique_id;
1656
1657 // get configuration
1658 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1659
1660 // get userPreferences ID
1661 unique_id = getUserPasswordID(config, userPreferences);
1662
1663 // extract
1664 (void) __extract_password(NULL,
1665 config,
1666 kSCPropNetPPPAuthPassword,
1667 kSCPropNetPPPAuthPasswordEncryption,
1668 kSCValNetPPPAuthPasswordEncryptionKeychain,
1669 unique_id,
1670 &password);
1671
1672 if (config != NULL) CFRelease(config);
1673 break;
1674 }
1675
1676 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
1677 CFDictionaryRef config;
1678 CFStringRef shared_id;
1679
1680 // get configuration
1681 config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
1682 interface,
1683 kSCEntNetIPSec);
1684
1685 // get sharedSecret ID
1686 shared_id = copyUserSharedSecretID(config, userPreferences);
1687
1688 // extract
1689 (void) __extract_password(NULL,
1690 config,
1691 kSCPropNetIPSecSharedSecret,
1692 kSCPropNetIPSecSharedSecretEncryption,
1693 kSCValNetIPSecSharedSecretEncryptionKeychain,
1694 shared_id,
1695 &password);
1696
1697 if (config != NULL) CFRelease(config);
1698 CFRelease(shared_id);
1699 break;
1700 }
1701
1702 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
1703 CFDictionaryRef config;
1704 CFStringRef xauth_id;
1705
1706 // get configuration
1707 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1708
1709 // get XAuth ID
1710 xauth_id = copyUserXAuthID(config, userPreferences);
1711
1712 // extract
1713 (void) __extract_password(NULL,
1714 config,
1715 kSCPropNetIPSecXAuthPassword,
1716 kSCPropNetIPSecXAuthPasswordEncryption,
1717 kSCValNetIPSecXAuthPasswordEncryptionKeychain,
1718 xauth_id,
1719 &password);
1720
1721 if (config != NULL) CFRelease(config);
1722 CFRelease(xauth_id);
1723 break;
1724 }
1725
1726 default :
1727 _SCErrorSet(kSCStatusInvalidArgument);
1728 return NULL;
1729 }
1730
1731 return password;
1732 }
1733
1734
1735 Boolean
1736 SCUserPreferencesRemoveInterfacePassword(SCUserPreferencesRef userPreferences,
1737 SCNetworkInterfaceRef interface,
1738 SCNetworkInterfacePasswordType passwordType)
1739 {
1740 Boolean ok = FALSE;
1741
1742 if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
1743 return FALSE;
1744 }
1745
1746 switch (passwordType) {
1747 case kSCNetworkInterfacePasswordTypePPP : {
1748 CFDictionaryRef config;
1749 CFDictionaryRef newConfig = NULL;
1750 CFStringRef unique_id;
1751
1752 // get configuration
1753 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1754
1755 // get userPreferences ID
1756 unique_id = getUserPasswordID(config, userPreferences);
1757
1758 // remove password
1759 ok = __remove_password(NULL,
1760 config,
1761 kSCPropNetPPPAuthPassword,
1762 kSCPropNetPPPAuthPasswordEncryption,
1763 kSCValNetPPPAuthPasswordEncryptionKeychain,
1764 unique_id,
1765 &newConfig);
1766 if (ok) {
1767 ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
1768 if (newConfig != NULL) CFRelease(newConfig);
1769 }
1770
1771 if (config != NULL) CFRelease(config);
1772 break;
1773 }
1774
1775 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
1776 CFDictionaryRef config;
1777 CFDictionaryRef newConfig = NULL;
1778 CFStringRef shared_id;
1779
1780 // get configuration
1781 config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
1782 interface,
1783 kSCEntNetIPSec);
1784
1785 // get sharedSecret ID
1786 shared_id = copyUserSharedSecretID(config, userPreferences);
1787
1788 // remove password
1789 ok = __remove_password(NULL,
1790 config,
1791 kSCPropNetIPSecSharedSecret,
1792 kSCPropNetIPSecSharedSecretEncryption,
1793 kSCValNetIPSecSharedSecretEncryptionKeychain,
1794 shared_id,
1795 &newConfig);
1796 if (ok) {
1797 ok = SCUserPreferencesSetExtendedInterfaceConfiguration(userPreferences,
1798 interface,
1799 kSCEntNetIPSec,
1800 newConfig);
1801 if (newConfig != NULL) CFRelease(newConfig);
1802 }
1803
1804 if (config != NULL) CFRelease(config);
1805 CFRelease(shared_id);
1806 break;
1807 }
1808
1809 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
1810 CFDictionaryRef config;
1811 CFDictionaryRef newConfig = NULL;
1812 CFStringRef xauth_id;
1813
1814 // get configuration
1815 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1816
1817 // get XAuth ID
1818 xauth_id = copyUserXAuthID(config, userPreferences);
1819
1820 // remove password
1821 ok = __remove_password(NULL,
1822 config,
1823 kSCPropNetIPSecXAuthPassword,
1824 kSCPropNetIPSecXAuthPasswordEncryption,
1825 kSCValNetIPSecXAuthPasswordEncryptionKeychain,
1826 xauth_id,
1827 &newConfig);
1828 if (ok) {
1829 ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
1830 if (newConfig != NULL) CFRelease(newConfig);
1831 }
1832
1833 if (config != NULL) CFRelease(config);
1834 CFRelease(xauth_id);
1835 break;
1836 }
1837
1838 default :
1839 _SCErrorSet(kSCStatusInvalidArgument);
1840 return FALSE;
1841 }
1842
1843 return ok;
1844 }
1845
1846
1847 Boolean
1848 SCUserPreferencesSetInterfacePassword(SCUserPreferencesRef userPreferences,
1849 SCNetworkInterfaceRef interface,
1850 SCNetworkInterfacePasswordType passwordType,
1851 CFDataRef password,
1852 CFDictionaryRef options)
1853 {
1854 CFStringRef account = NULL;
1855 CFBundleRef bundle;
1856 CFDictionaryRef config;
1857 CFStringRef description = NULL;
1858 CFStringRef label = NULL;
1859 Boolean ok = FALSE;
1860
1861 if (!checkUserPreferencesPassword(userPreferences, interface, passwordType)) {
1862 return FALSE;
1863 }
1864
1865 bundle = _SC_CFBundleGet();
1866
1867 switch (passwordType) {
1868 case kSCNetworkInterfacePasswordTypePPP : {
1869 CFStringRef unique_id;
1870
1871 // get configuration
1872 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1873
1874 // get userPreferences ID
1875 unique_id = getUserPasswordID(config, userPreferences);
1876
1877 // User prefs auth name --> keychain "Account"
1878 if (config != NULL) {
1879 account = CFDictionaryGetValue(config, kSCPropNetPPPAuthName);
1880 }
1881
1882 // User prefs "name" --> keychain "Name"
1883 label = SCUserPreferencesCopyName(userPreferences);
1884
1885 // "PPP Password" --> keychain "Kind"
1886 if (bundle != NULL) {
1887 description = CFBundleCopyLocalizedString(bundle,
1888 CFSTR("KEYCHAIN_KIND_PPP_PASSWORD"),
1889 CFSTR("PPP Password"),
1890 NULL);
1891 }
1892
1893 // store password
1894 ok = _SCSecKeychainPasswordItemSet(NULL,
1895 unique_id,
1896 (label != NULL) ? label : CFSTR("Network Connection"),
1897 (description != NULL) ? description : CFSTR("PPP Password"),
1898 account,
1899 password,
1900 options);
1901 if (ok) {
1902 CFMutableDictionaryRef newConfig;
1903
1904 if (config != NULL) {
1905 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
1906 } else {
1907 newConfig = CFDictionaryCreateMutable(NULL,
1908 0,
1909 &kCFTypeDictionaryKeyCallBacks,
1910 &kCFTypeDictionaryValueCallBacks);
1911 }
1912 CFDictionarySetValue(newConfig,
1913 kSCPropNetPPPAuthPassword,
1914 unique_id);
1915 CFDictionarySetValue(newConfig,
1916 kSCPropNetPPPAuthPasswordEncryption,
1917 kSCValNetPPPAuthPasswordEncryptionKeychain);
1918 ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
1919 CFRelease(newConfig);
1920 }
1921
1922 if (config != NULL) CFRelease(config);
1923 if (description != NULL) CFRelease(description);
1924 if (label != NULL) CFRelease(label);
1925 break;
1926 }
1927
1928 case kSCNetworkInterfacePasswordTypeIPSecSharedSecret : {
1929 CFStringRef shared_id;
1930
1931 // get configuration
1932 config = SCUserPreferencesCopyExtendedInterfaceConfiguration(userPreferences,
1933 interface,
1934 kSCEntNetIPSec);
1935
1936 // get sharedSecret ID
1937 shared_id = copyUserSharedSecretID(config, userPreferences);
1938
1939 // User prefs "name" --> keychain "Name"
1940 label = SCUserPreferencesCopyName(userPreferences);
1941
1942 // "IPSec Shared Secret" --> keychain "Kind"
1943 if (bundle != NULL) {
1944 description = CFBundleCopyLocalizedString(bundle,
1945 CFSTR("KEYCHAIN_KIND_IPSEC_SHARED_SECRET"),
1946 CFSTR("IPSec Shared Secret"),
1947 NULL);
1948 }
1949
1950 // set password
1951 ok = _SCSecKeychainPasswordItemSet(NULL,
1952 shared_id,
1953 (label != NULL) ? label : CFSTR("VPN Connection"),
1954 (description != NULL) ? description : CFSTR("IPSec Shared Secret"),
1955 NULL,
1956 password,
1957 options);
1958 if (ok) {
1959 CFMutableDictionaryRef newConfig = NULL;
1960
1961 if (config != NULL) {
1962 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
1963 } else {
1964 newConfig = CFDictionaryCreateMutable(NULL,
1965 0,
1966 &kCFTypeDictionaryKeyCallBacks,
1967 &kCFTypeDictionaryValueCallBacks);
1968 }
1969 CFDictionarySetValue(newConfig,
1970 kSCPropNetIPSecSharedSecret,
1971 shared_id);
1972 CFDictionarySetValue(newConfig,
1973 kSCPropNetIPSecSharedSecretEncryption,
1974 kSCValNetIPSecSharedSecretEncryptionKeychain);
1975 ok = SCUserPreferencesSetExtendedInterfaceConfiguration(userPreferences,
1976 interface,
1977 kSCEntNetIPSec,
1978 newConfig);
1979 CFRelease(newConfig);
1980 }
1981
1982 if (config != NULL) CFRelease(config);
1983 if (description != NULL) CFRelease(description);
1984 if (label != NULL) CFRelease(label);
1985 CFRelease(shared_id);
1986 break;
1987 }
1988
1989 case kSCNetworkInterfacePasswordTypeIPSecXAuth : {
1990 CFStringRef xauth_id;
1991
1992 // get configuration
1993 config = SCUserPreferencesCopyInterfaceConfiguration(userPreferences, interface);
1994
1995 // get XAuth ID
1996 xauth_id = copyUserXAuthID(config, userPreferences);
1997
1998 // User prefs XAuth name --> keychain "Account"
1999 if (config != NULL) {
2000 account = CFDictionaryGetValue(config, kSCPropNetIPSecXAuthName);
2001 }
2002
2003 // User prefs "name" --> keychain "Name"
2004 label = SCUserPreferencesCopyName(userPreferences);
2005
2006 // "IPSec XAuth Password" --> keychain "Kind"
2007 if (bundle != NULL) {
2008 description = CFBundleCopyLocalizedString(bundle,
2009 CFSTR("KEYCHAIN_KIND_IPSEC_XAUTH_PASSWORD"),
2010 CFSTR("IPSec XAuth Password"),
2011 NULL);
2012 }
2013
2014 // store password
2015 ok = _SCSecKeychainPasswordItemSet(NULL,
2016 xauth_id,
2017 (label != NULL) ? label : CFSTR("VPN Connection"),
2018 (description != NULL) ? description : CFSTR("IPSec XAuth Password"),
2019 account,
2020 password,
2021 options);
2022 if (ok) {
2023 CFMutableDictionaryRef newConfig;
2024
2025 if (config != NULL) {
2026 newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
2027 } else {
2028 newConfig = CFDictionaryCreateMutable(NULL,
2029 0,
2030 &kCFTypeDictionaryKeyCallBacks,
2031 &kCFTypeDictionaryValueCallBacks);
2032 }
2033 CFDictionarySetValue(newConfig,
2034 kSCPropNetIPSecXAuthPassword,
2035 xauth_id);
2036 CFDictionarySetValue(newConfig,
2037 kSCPropNetIPSecXAuthPasswordEncryption,
2038 kSCValNetIPSecXAuthPasswordEncryptionKeychain);
2039 ok = SCUserPreferencesSetInterfaceConfiguration(userPreferences, interface, newConfig);
2040 CFRelease(newConfig);
2041 }
2042
2043 if (config != NULL) CFRelease(config);
2044 if (description != NULL) CFRelease(description);
2045 if (label != NULL) CFRelease(label);
2046 CFRelease(xauth_id);
2047 break;
2048 }
2049
2050 default :
2051 _SCErrorSet(kSCStatusInvalidArgument);
2052 return FALSE;
2053 }
2054
2055 return ok;
2056 }