2 * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * April 14, 2004 Christophe Allie <callie@apple.com>
30 * December 20, 2002 Christophe Allie <callie@apple.com>
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <CoreFoundation/CFRuntime.h>
38 #include <Security/Security.h>
39 #include "dy_framework.h"
41 #include <SystemConfiguration/SystemConfiguration.h>
42 #include <SystemConfiguration/SCPrivate.h>
43 #include <SystemConfiguration/SCValidation.h>
45 #include <servers/bootstrap.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
53 #include <sys/ioctl.h>
54 #include <sys/socket.h>
57 #include <ppp/ppp_msg.h>
58 #include <ppp/PPPControllerPriv.h>
59 #include "pppcontroller.h"
60 #include <ppp/pppcontroller_types.h>
66 /* base CFType information */
73 SCNetworkServiceRef service
;
75 /* ref to PPP controller for control messages */
76 mach_port_t session_port
;
78 /* ref to PPP controller for notification messages */
79 CFMachPortRef notify_port
;
81 /* run loop source, callout, context, rl scheduling info */
82 CFRunLoopSourceRef rls
;
83 SCNetworkConnectionCallBack rlsFunction
;
84 SCNetworkConnectionContext rlsContext
;
85 CFMutableArrayRef rlList
;
90 } SCNetworkConnectionPrivate
, *SCNetworkConnectionPrivateRef
;
93 static __inline__ CFTypeRef
94 isA_SCNetworkConnection(CFTypeRef obj
)
96 return (isA_CFType(obj
, SCNetworkConnectionGetTypeID()));
101 __SCNetworkConnectionCopyDescription(CFTypeRef cf
)
103 CFAllocatorRef allocator
= CFGetAllocator(cf
);
104 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
105 CFMutableStringRef result
;
107 result
= CFStringCreateMutable(allocator
, 0);
108 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkConnection, %p [%p]> {"), cf
, allocator
);
109 CFStringAppendFormat(result
, NULL
, CFSTR("service = %p"), connectionPrivate
->service
);
110 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
) {
111 CFStringAppendFormat(result
, NULL
, CFSTR(", server port = %p"), connectionPrivate
->session_port
);
113 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
120 __SCNetworkConnectionDeallocate(CFTypeRef cf
)
122 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
124 if (connectionPrivate
->debug
) {
125 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionDeallocate (0x%x)"), connectionPrivate
);
128 /* release resources */
129 pthread_mutex_destroy(&connectionPrivate
->lock
);
131 if (connectionPrivate
->rlList
!= NULL
) {
132 CFRunLoopSourceInvalidate(connectionPrivate
->rls
);
133 CFRelease(connectionPrivate
->rls
);
134 CFRelease(connectionPrivate
->rlList
);
137 if (connectionPrivate
->notify_port
!= NULL
) {
138 CFMachPortInvalidate(connectionPrivate
->notify_port
);
139 CFRelease(connectionPrivate
->notify_port
);
142 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
)
143 mach_port_destroy(mach_task_self(), connectionPrivate
->session_port
);
145 if (connectionPrivate
->rlsContext
.release
!= NULL
)
146 (*connectionPrivate
->rlsContext
.release
)(connectionPrivate
->rlsContext
.info
);
148 CFRelease(connectionPrivate
->service
);
154 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
156 static CFTypeID __kSCNetworkConnectionTypeID
= _kCFRuntimeNotATypeID
;
158 static const CFRuntimeClass __SCNetworkConnectionClass
= {
160 "SCNetworkConnection", // className
163 __SCNetworkConnectionDeallocate
, // dealloc
166 NULL
, // copyFormattingDesc
167 __SCNetworkConnectionCopyDescription
// copyDebugDesc
172 __SCNetworkConnectionInitialize(void)
174 __kSCNetworkConnectionTypeID
= _CFRuntimeRegisterClass(&__SCNetworkConnectionClass
);
179 static SCNetworkConnectionStatus
180 __SCNetworkConnectionConvertStatus(int state
)
182 SCNetworkConnectionStatus status
= kSCNetworkConnectionDisconnected
;
186 case PPP_CONNECTLINK
:
188 case PPP_AUTHENTICATE
:
192 status
= kSCNetworkConnectionConnecting
;
195 case PPP_DISCONNECTLINK
:
196 status
= kSCNetworkConnectionDisconnecting
;
200 status
= kSCNetworkConnectionConnected
;
206 status
= kSCNetworkConnectionDisconnected
;
213 __SCNetworkConnectionCallBack(CFMachPortRef port
, void * msg
, CFIndex size
, void * info
)
215 mach_msg_empty_rcv_t
* buf
= msg
;
216 SCNetworkConnectionRef connection
= (SCNetworkConnectionRef
)info
;
217 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
219 void (*context_release
)(const void *);
220 int error
= kSCStatusFailed
;
221 mach_msg_id_t msgid
= buf
->header
.msgh_id
;
222 int phase
= PPP_IDLE
;
223 SCNetworkConnectionCallBack rlsFunction
;
224 kern_return_t status
;
225 SCNetworkConnectionStatus scstatus
;
227 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
228 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionCallBack: PPPController server died"));
230 status
= pppcontroller_getstatus(connectionPrivate
->session_port
, &phase
, &error
);
233 if (connectionPrivate
->rls
== NULL
) {
237 rlsFunction
= connectionPrivate
->rlsFunction
;
238 if (rlsFunction
== NULL
) {
242 if ((connectionPrivate
->rlsContext
.retain
!= NULL
) && (connectionPrivate
->rlsContext
.info
!= NULL
)) {
243 context_info
= (void *)(*connectionPrivate
->rlsContext
.retain
)(connectionPrivate
->rlsContext
.info
);
244 context_release
= connectionPrivate
->rlsContext
.release
;
246 context_info
= connectionPrivate
->rlsContext
.info
;
247 context_release
= NULL
;
250 scstatus
= __SCNetworkConnectionConvertStatus(phase
);
252 (*rlsFunction
)(connection
, scstatus
, context_info
);
253 if ((context_release
!= NULL
) && (context_info
!= NULL
)) {
254 (*context_release
)(context_info
);
262 #pragma mark SCNetworkConnection APIs
266 pppMPCopyDescription(const void *info
)
268 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)info
;
270 return CFStringCreateWithFormat(NULL
,
272 CFSTR("<SCNetworkConnection MP %p> {service = %@, callout = %p}"),
274 connectionPrivate
->service
,
275 connectionPrivate
->rlsFunction
);
279 static SCNetworkConnectionPrivateRef
280 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator
,
281 SCNetworkServiceRef service
,
282 SCNetworkConnectionCallBack callout
,
283 SCNetworkConnectionContext
*context
)
285 SCNetworkConnectionPrivateRef connectionPrivate
= NULL
;
290 /* initialize runtime */
291 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
293 /* allocate NetworkConnection */
294 size
= sizeof(SCNetworkConnectionPrivate
) - sizeof(CFRuntimeBase
);
295 connectionPrivate
= (SCNetworkConnectionPrivateRef
)_CFRuntimeCreateInstance(allocator
, __kSCNetworkConnectionTypeID
, size
, NULL
);
296 if (connectionPrivate
== NULL
) {
300 /* zero the data structure */
301 bzero(((u_char
*)connectionPrivate
)+sizeof(CFRuntimeBase
), size
);
303 pthread_mutex_init(&connectionPrivate
->lock
, NULL
);
305 /* save the service */
306 connectionPrivate
->service
= CFRetain(service
);
308 /* get the debug environment variable */
309 envdebug
= getenv("PPPDebug");
311 if (sscanf(envdebug
, "%d", &connectionPrivate
->debug
) != 1)
312 connectionPrivate
->debug
= 1; /* PPPDebug value is invalid, set debug to 1 */
315 connectionPrivate
->rlsFunction
= callout
;
318 bcopy(context
, &connectionPrivate
->rlsContext
, sizeof(SCNetworkConnectionContext
));
319 if (context
->retain
!= NULL
) {
320 connectionPrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
324 if (connectionPrivate
->debug
) {
325 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCreate (0x%x) succeeded for service : %@"), connectionPrivate
, service
);
328 /* success, return the connection reference */
329 return connectionPrivate
;
333 if (connectionPrivate
->debug
)
334 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCreate (0x%x) failed for service : %@"), connectionPrivate
, service
);
336 /* failure, clean up and leave */
337 if (connectionPrivate
!= NULL
) {
338 CFRelease(connectionPrivate
);
341 _SCErrorSet(kSCStatusFailed
);
347 __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate
)
351 CFDataRef dataRef
= NULL
;
352 int error
= kSCStatusFailed
;
353 mach_port_t notify_port
= MACH_PORT_NULL
;
354 mach_port_t port_old
= MACH_PORT_NULL
;
355 mach_port_t server
= MACH_PORT_NULL
;
356 kern_return_t status
;
357 mach_port_t unpriv_bootstrap_port
= MACH_PORT_NULL
;
359 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
) {
360 return connectionPrivate
->session_port
;
363 pthread_mutex_lock(&connectionPrivate
->lock
);
365 if (bootstrap_look_up(bootstrap_port
, PPPCONTROLLER_SERVER
, &server
) != BOOTSTRAP_SUCCESS
) {
366 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("PPP Controller server not found"));
370 if (!_SCSerializeString(SCNetworkServiceGetServiceID(connectionPrivate
->service
), &dataRef
, &data
, &dataLen
)) {
374 status
= bootstrap_unprivileged(bootstrap_port
, &unpriv_bootstrap_port
);
375 if (status
!= BOOTSTRAP_SUCCESS
) {
379 if (connectionPrivate
->rlsFunction
!= NULL
) {
380 CFMachPortContext context
= { 0
381 , (void *)connectionPrivate
384 , pppMPCopyDescription
387 /* allocate port (for server response) */
388 connectionPrivate
->notify_port
= CFMachPortCreate(NULL
, __SCNetworkConnectionCallBack
, &context
, NULL
);
390 /* request a notification when/if the server dies */
391 notify_port
= CFMachPortGetPort(connectionPrivate
->notify_port
);
392 status
= mach_port_request_notification(mach_task_self(),
394 MACH_NOTIFY_NO_SENDERS
,
397 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
399 if (status
!= KERN_SUCCESS
) {
404 status
= pppcontroller_attach(server
, data
, dataLen
, unpriv_bootstrap_port
, notify_port
,
405 &connectionPrivate
->session_port
, &error
);
406 if (status
!= KERN_SUCCESS
) {
407 error
= kSCStatusFailed
;
412 if (dataRef
!= NULL
) CFRelease(dataRef
);
414 if (unpriv_bootstrap_port
!= MACH_PORT_NULL
) {
415 mach_port_deallocate(mach_task_self(), unpriv_bootstrap_port
);
418 if (error
!= kSCStatusOK
) {
419 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
) {
420 mach_port_destroy(mach_task_self(), connectionPrivate
->session_port
);
421 connectionPrivate
->session_port
= MACH_PORT_NULL
;
423 if (connectionPrivate
->notify_port
!= NULL
) {
424 CFMachPortInvalidate(connectionPrivate
->notify_port
);
425 CFRelease(connectionPrivate
->notify_port
);
426 connectionPrivate
->notify_port
= NULL
;
431 pthread_mutex_unlock(&connectionPrivate
->lock
);
433 return connectionPrivate
->session_port
;
438 SCNetworkConnectionGetTypeID(void) {
439 pthread_once(&initialized
, __SCNetworkConnectionInitialize
); /* initialize runtime */
440 return __kSCNetworkConnectionTypeID
;
444 CFArrayRef
/* of SCNetworkServiceRef's */
445 SCNetworkConnectionCopyAvailableServices(SCNetworkSetRef set
)
447 CFMutableArrayRef available
;
448 Boolean tempSet
= FALSE
;
451 SCPreferencesRef prefs
;
453 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCNetworkConnectionCopyAvailableServices"), NULL
);
454 set
= SCNetworkSetCopyCurrent(prefs
);
459 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
464 services
= SCNetworkSetCopyServices(set
);
465 if (services
!= NULL
) {
469 n
= CFArrayGetCount(services
);
470 for (i
= 0; i
< n
; i
++) {
471 SCNetworkInterfaceRef interface
;
472 CFStringRef interfaceType
;
473 SCNetworkServiceRef service
;
475 service
= CFArrayGetValueAtIndex(services
, i
);
476 interface
= SCNetworkServiceGetInterface(service
);
477 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
478 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypePPP
)) {
479 CFArrayAppendValue(available
, service
);
487 if (tempSet
) CFRelease(set
);
492 SCNetworkConnectionRef
493 SCNetworkConnectionCreateWithService(CFAllocatorRef allocator
,
494 SCNetworkServiceRef service
,
495 SCNetworkConnectionCallBack callout
,
496 SCNetworkConnectionContext
*context
)
498 SCNetworkConnectionPrivateRef connectionPrivate
;
500 if (!isA_SCNetworkService(service
)) {
501 _SCErrorSet(kSCStatusInvalidArgument
);
505 connectionPrivate
= __SCNetworkConnectionCreatePrivate(allocator
, service
, callout
, context
);
506 return (SCNetworkConnectionRef
)connectionPrivate
;
510 SCNetworkConnectionRef
511 SCNetworkConnectionCreateWithServiceID(CFAllocatorRef allocator
,
512 CFStringRef serviceID
,
513 SCNetworkConnectionCallBack callout
,
514 SCNetworkConnectionContext
*context
)
516 SCNetworkConnectionRef connection
;
517 SCPreferencesRef prefs
;
518 SCNetworkServiceRef service
;
520 if (!isA_CFString(serviceID
)) {
521 _SCErrorSet(kSCStatusInvalidArgument
);
525 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCNetworkConnectionCreateWithServiceID"), NULL
);
530 service
= SCNetworkServiceCopy(prefs
, serviceID
);
532 if (service
== NULL
) {
536 connection
= SCNetworkConnectionCreateWithService(allocator
, service
, callout
, context
);
544 SCNetworkConnectionCopyServiceID(SCNetworkConnectionRef connection
)
546 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
547 CFStringRef serviceID
;
549 if (!isA_SCNetworkConnection(connection
)) {
550 _SCErrorSet(kSCStatusInvalidArgument
);
554 serviceID
= SCNetworkServiceGetServiceID(connectionPrivate
->service
);
555 return CFRetain(serviceID
);
560 SCNetworkConnectionCopyStatistics(SCNetworkConnectionRef connection
)
562 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
563 xmlDataOut_t data
= NULL
;
564 mach_msg_type_number_t datalen
;
565 int error
= kSCStatusFailed
;
566 mach_port_t session_port
;
567 CFPropertyListRef statistics
= NULL
;
568 kern_return_t status
;
570 if (!isA_SCNetworkConnection(connection
)) {
571 _SCErrorSet(kSCStatusInvalidArgument
);
575 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
576 if (session_port
== MACH_PORT_NULL
) {
577 _SCErrorSet(kSCStatusInvalidArgument
);
581 status
= pppcontroller_copystatistics(session_port
, &data
, &datalen
, &error
);
582 if (status
!= KERN_SUCCESS
) {
586 if (error
!= kSCStatusOK
) {
590 if ((data
== NULL
) ||
591 !_SCUnserialize(&statistics
, NULL
, data
, datalen
) ||
592 !isA_CFDictionary(statistics
)) {
600 if (statistics
) CFRelease(statistics
);
607 SCNetworkConnectionGetService(SCNetworkConnectionRef connection
)
609 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
611 if (!isA_SCNetworkConnection(connection
)) {
612 _SCErrorSet(kSCStatusInvalidArgument
);
616 return connectionPrivate
->service
;
620 SCNetworkConnectionStatus
621 SCNetworkConnectionGetStatus(SCNetworkConnectionRef connection
)
623 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
624 int error
= kSCStatusFailed
;
626 SCNetworkConnectionStatus scstatus
;
627 mach_port_t session_port
;
628 kern_return_t status
;
630 if (!isA_SCNetworkConnection(connection
)) {
631 _SCErrorSet(kSCStatusInvalidArgument
);
632 return kSCNetworkConnectionInvalid
;
635 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
636 if (session_port
== MACH_PORT_NULL
) {
637 _SCErrorSet(kSCStatusInvalidArgument
);
638 return kSCNetworkConnectionInvalid
;
641 status
= pppcontroller_getstatus(session_port
, &phase
, &error
);
642 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
643 return kSCNetworkConnectionDisconnected
;
646 scstatus
= __SCNetworkConnectionConvertStatus(phase
);
652 SCNetworkConnectionCopyExtendedStatus(SCNetworkConnectionRef connection
)
654 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
655 xmlDataOut_t data
= NULL
;
656 mach_msg_type_number_t datalen
;
657 int error
= kSCStatusFailed
;
658 CFPropertyListRef extstatus
= NULL
;
659 mach_port_t session_port
;
660 kern_return_t status
;
662 if (!isA_SCNetworkConnection(connection
)) {
663 _SCErrorSet(kSCStatusInvalidArgument
);
667 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
668 if (session_port
== MACH_PORT_NULL
) {
669 _SCErrorSet(kSCStatusInvalidArgument
);
673 status
= pppcontroller_copyextendedstatus(session_port
, &data
, &datalen
, &error
);
674 if (status
!= KERN_SUCCESS
) {
678 if (error
!= kSCStatusOK
) {
682 if ((data
== NULL
) ||
683 !_SCUnserialize(&extstatus
, NULL
, data
, datalen
) ||
684 !isA_CFDictionary(extstatus
)) {
692 if (extstatus
) CFRelease(extstatus
);
699 SCNetworkConnectionStart(SCNetworkConnectionRef connection
,
700 CFDictionaryRef userOptions
,
703 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
704 CFDataRef dataref
= NULL
;
707 int error
= kSCStatusFailed
;
708 mach_port_t session_port
;
709 kern_return_t status
;
711 if (!isA_SCNetworkConnection(connection
)) {
712 _SCErrorSet(kSCStatusInvalidArgument
);
716 if ((userOptions
!= NULL
) && !isA_CFDictionary(userOptions
)) {
717 _SCErrorSet(kSCStatusInvalidArgument
);
721 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
722 if (session_port
== MACH_PORT_NULL
) {
723 _SCErrorSet(kSCStatusInvalidArgument
);
727 if (connectionPrivate
->debug
) {
728 CFMutableDictionaryRef mdict
= NULL
;
730 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x)"), connectionPrivate
);
732 if (userOptions
!= NULL
) {
733 CFDictionaryRef dict
;
734 CFStringRef encryption
;
735 CFMutableDictionaryRef new_dict
;
737 /* special code to remove secret information */
738 mdict
= CFDictionaryCreateMutableCopy(NULL
, 0, userOptions
);
740 dict
= CFDictionaryGetValue(mdict
, kSCEntNetPPP
);
741 if (isA_CFDictionary(dict
)) {
742 encryption
= CFDictionaryGetValue(dict
, kSCPropNetPPPAuthPasswordEncryption
);
743 if (!isA_CFString(encryption
) ||
744 !CFEqual(encryption
, kSCValNetPPPAuthPasswordEncryptionKeychain
)) {
745 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
746 CFDictionaryReplaceValue(new_dict
, kSCPropNetPPPAuthPassword
, CFSTR("******"));
747 CFDictionarySetValue(mdict
, kSCEntNetPPP
, new_dict
);
752 dict
= CFDictionaryGetValue(mdict
, kSCEntNetL2TP
);
753 if (isA_CFDictionary(dict
)) {
754 encryption
= CFDictionaryGetValue(dict
, kSCPropNetL2TPIPSecSharedSecretEncryption
);
755 if (!isA_CFString(encryption
) ||
756 !CFEqual(encryption
, kSCValNetL2TPIPSecSharedSecretEncryptionKeychain
)) {
757 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
758 CFDictionaryReplaceValue(new_dict
, kSCPropNetL2TPIPSecSharedSecret
, CFSTR("******"));
759 CFDictionarySetValue(mdict
, kSCEntNetL2TP
, new_dict
);
764 dict
= CFDictionaryGetValue(mdict
, kSCEntNetIPSec
);
765 if (isA_CFDictionary(dict
)) {
766 encryption
= CFDictionaryGetValue(dict
, kSCPropNetIPSecSharedSecretEncryption
);
767 if (!isA_CFString(encryption
) ||
768 !CFEqual(encryption
, kSCValNetIPSecSharedSecretEncryptionKeychain
)) {
769 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
770 CFDictionaryReplaceValue(new_dict
, kSCPropNetIPSecSharedSecret
, CFSTR("******"));
771 CFDictionarySetValue(mdict
, kSCEntNetIPSec
, new_dict
);
777 SCLog(TRUE
, LOG_DEBUG
, CFSTR("User options: %@"), mdict
);
778 if (mdict
!= NULL
) CFRelease(mdict
);
781 if (userOptions
&& !_SCSerialize(userOptions
, &dataref
, &data
, &datalen
)) {
785 status
= pppcontroller_start(session_port
, data
, datalen
, linger
, &error
);
786 if (status
!= KERN_SUCCESS
) {
795 if (connectionPrivate
->debug
)
796 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x), return: %d"), connectionPrivate
, error
);
798 if (error
!= kSCStatusOK
) {
802 /* connection is now started */
807 if (dataref
) CFRelease(dataref
);
814 SCNetworkConnectionStop(SCNetworkConnectionRef connection
,
815 Boolean forceDisconnect
)
817 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
818 int error
= kSCStatusFailed
;
819 mach_port_t session_port
;
820 kern_return_t status
;
822 if (!isA_SCNetworkConnection(connection
)) {
823 _SCErrorSet(kSCStatusInvalidArgument
);
827 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
828 if (session_port
== MACH_PORT_NULL
) {
829 _SCErrorSet(kSCStatusInvalidArgument
);
833 if (connectionPrivate
->debug
)
834 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x)"), connectionPrivate
);
836 status
= pppcontroller_stop(session_port
, forceDisconnect
, &error
);
837 if (status
!= KERN_SUCCESS
) {
841 if (connectionPrivate
->debug
)
842 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x), return: %d"), connectionPrivate
, error
);
844 if (error
!= kSCStatusOK
) {
848 /* connection is now disconnecting */
859 SCNetworkConnectionSuspend(SCNetworkConnectionRef connection
)
861 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
862 int error
= kSCStatusFailed
;
863 mach_port_t session_port
;
864 kern_return_t status
;
866 if (!isA_SCNetworkConnection(connection
)) {
867 _SCErrorSet(kSCStatusInvalidArgument
);
871 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
872 if (session_port
== MACH_PORT_NULL
) {
873 _SCErrorSet(kSCStatusInvalidArgument
);
877 if (connectionPrivate
->debug
)
878 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x)"), connectionPrivate
);
880 status
= pppcontroller_suspend(session_port
, &error
);
881 if (status
!= KERN_SUCCESS
) {
885 if (connectionPrivate
->debug
)
886 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x), return: %d"), connectionPrivate
, error
);
888 if (error
!= kSCStatusOK
) {
892 /* connection is now suspended */
903 SCNetworkConnectionResume(SCNetworkConnectionRef connection
)
905 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
906 int error
= kSCStatusFailed
;
907 mach_port_t session_port
;
908 kern_return_t status
;
910 if (!isA_SCNetworkConnection(connection
)) {
911 _SCErrorSet(kSCStatusInvalidArgument
);
915 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
916 if (session_port
== MACH_PORT_NULL
) {
917 _SCErrorSet(kSCStatusInvalidArgument
);
921 if (connectionPrivate
->debug
)
922 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x)"), connectionPrivate
);
924 status
= pppcontroller_resume(session_port
, &error
);
925 if (status
!= KERN_SUCCESS
) {
929 if (connectionPrivate
->debug
)
930 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x), return: %d"), connectionPrivate
, error
);
932 if (error
!= kSCStatusOK
) {
936 /* connection is now resume */
947 SCNetworkConnectionCopyUserOptions(SCNetworkConnectionRef connection
)
949 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
950 xmlDataOut_t data
= NULL
;
951 mach_msg_type_number_t datalen
;
952 int error
= kSCStatusFailed
;
953 mach_port_t session_port
;
954 kern_return_t status
;
955 CFPropertyListRef userOptions
= NULL
;
957 if (!isA_SCNetworkConnection(connection
)) {
958 _SCErrorSet(kSCStatusInvalidArgument
);
962 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
963 if (session_port
== MACH_PORT_NULL
) {
964 _SCErrorSet(kSCStatusInvalidArgument
);
968 status
= pppcontroller_copyuseroptions(session_port
, &data
, &datalen
, &error
);
969 if (status
!= KERN_SUCCESS
) {
973 if (error
!= kSCStatusOK
) {
977 // no data were used, return an empty dictionary
979 CFDictionaryRef dict
;
981 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
983 _SCErrorSet(kSCStatusFailed
); // XXX
988 if (!_SCUnserialize(&userOptions
, NULL
, data
, datalen
) ||
989 !isA_CFDictionary(userOptions
)) {
997 if (userOptions
) CFRelease(userOptions
);
1004 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
1005 CFRunLoopRef runLoop
,
1006 CFStringRef runLoopMode
)
1008 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
1009 int error
= kSCStatusFailed
;
1010 mach_port_t session_port
;
1011 kern_return_t status
;
1013 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
1014 _SCErrorSet(kSCStatusInvalidArgument
);
1018 if (connectionPrivate
->rlsFunction
== NULL
) {
1019 _SCErrorSet(kSCStatusInvalidArgument
);
1023 if ((connectionPrivate
->rlList
!= NULL
) &&
1024 _SC_isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
1025 /* already scheduled */
1026 _SCErrorSet(kSCStatusFailed
);
1030 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
1031 if (session_port
== MACH_PORT_NULL
) {
1032 _SCErrorSet(kSCStatusInvalidArgument
);
1036 if (connectionPrivate
->rlList
== NULL
) {
1037 status
= pppcontroller_notification(session_port
, 1, &error
);
1038 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
1043 connectionPrivate
->rls
= CFMachPortCreateRunLoopSource(NULL
, connectionPrivate
->notify_port
, 0);
1044 connectionPrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1047 CFRunLoopAddSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
1048 _SC_schedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
);
1055 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
1056 CFRunLoopRef runLoop
,
1057 CFStringRef runLoopMode
)
1059 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
1060 int error
= kSCStatusFailed
;
1061 mach_port_t session_port
;
1062 kern_return_t status
;
1064 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
1065 _SCErrorSet(kSCStatusInvalidArgument
);
1069 if ((connectionPrivate
->rlList
== NULL
) ||
1070 !_SC_unschedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
, FALSE
)) {
1071 /* if not currently scheduled */
1072 _SCErrorSet(kSCStatusFailed
);
1076 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
1077 if (session_port
== MACH_PORT_NULL
) {
1078 _SCErrorSet(kSCStatusInvalidArgument
);
1082 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
1084 if (CFArrayGetCount(connectionPrivate
->rlList
) == 0) {
1085 CFRelease(connectionPrivate
->rls
);
1086 connectionPrivate
->rls
= NULL
;
1087 CFRelease(connectionPrivate
->rlList
);
1088 connectionPrivate
->rlList
= NULL
;
1090 status
= pppcontroller_notification(session_port
, 0, &error
);
1091 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
1102 #pragma mark User level "dial" API
1105 #define k_NetworkConnect_Notification "com.apple.networkConnect"
1106 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
1107 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
1109 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
1110 #define k_Last_Service_Id_Key CFSTR("ServiceID")
1111 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
1114 /* Private Prototypes */
1115 static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
1116 static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
1117 static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
);
1118 static Boolean
SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
);
1119 static void addPasswordFromKeychain (SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
);
1120 static CFStringRef
copyPasswordFromKeychain (CFStringRef uniqueID
);
1121 static CFArrayRef
copyKeychainEnumerator (CFStringRef uniqueIdentifier
);
1123 static int notify_userprefs_token
= -1;
1126 * return TRUE if domain1 ends with domain2, and will check for trailing "."
1129 domainEndsWithDomain(CFStringRef domain1
, CFStringRef domain2
)
1132 Boolean ret
= FALSE
;
1133 CFStringRef s1
= NULL
;
1134 Boolean s1_created
= FALSE
;
1135 CFStringRef s2
= NULL
;
1136 Boolean s2_created
= FALSE
;
1138 if (CFStringHasSuffix(domain1
, CFSTR("."))) {
1140 range
.length
= CFStringGetLength(domain1
) - 1;
1141 s1
= CFStringCreateWithSubstring(NULL
, domain1
, range
);
1150 if (CFStringHasSuffix(domain2
, CFSTR("."))) {
1152 range
.length
= CFStringGetLength(domain2
) - 1;
1153 s2
= CFStringCreateWithSubstring(NULL
, domain2
, range
);
1162 ret
= CFStringHasSuffix(s1
, s2
);
1166 if (s1_created
) CFRelease(s1
);
1167 if (s2_created
) CFRelease(s2
);
1173 SCNetworkConnectionCopyUserPreferences(CFDictionaryRef selectionOptions
,
1174 CFStringRef
*serviceID
,
1175 CFDictionaryRef
*userOptions
)
1180 SCDynamicStoreRef session
;
1181 Boolean success
= FALSE
;
1185 envdebug
= getenv("PPPDebug");
1187 if (sscanf(envdebug
, "%d", &debug
) != 1)
1188 debug
= 1; /* PPPDebug value is invalid, set debug to 1 */
1191 if (notify_userprefs_token
== -1) {
1192 status
= notify_register_check(k_NetworkConnect_Notification
, ¬ify_userprefs_token
);
1193 if (status
!= NOTIFY_STATUS_OK
)
1194 notify_userprefs_token
= -1;
1197 notify_check(notify_userprefs_token
, &prefsChanged
);
1201 if (notify_userprefs_token
!= -1)
1202 notify_check(notify_userprefs_token
, &prefsChanged
);
1206 *userOptions
= NULL
;
1208 session
= SCDynamicStoreCreate(NULL
, CFSTR("SCNetworkConnection"), NULL
, NULL
);
1209 if (session
== NULL
) {
1210 fprintf(stderr
, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
1214 if (selectionOptions
!= NULL
) {
1215 Boolean catchAllFound
= FALSE
;
1216 CFIndex catchAllService
= 0;
1217 CFIndex catchAllConfig
= 0;
1218 CFStringRef hostName
= NULL
;
1219 CFStringRef priority
= NULL
;
1220 CFArrayRef serviceNames
= NULL
;
1221 CFDictionaryRef services
= NULL
;
1222 CFIndex serviceIndex
;
1223 CFIndex servicesCount
;
1225 hostName
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandHostName
);
1226 if (!isA_CFString(hostName
))
1229 // can't select anything
1230 if (hostName
== NULL
)
1231 goto done_selection
;
1233 priority
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandPriority
);
1234 if (!isA_CFString(priority
))
1235 priority
= kSCValNetPPPOnDemandPriorityDefault
;
1238 if (!isA_CFArray(serviceNames
))
1239 goto done_selection
;
1242 if (!isA_CFDictionary(services
))
1243 goto done_selection
;
1245 servicesCount
= CFArrayGetCount(serviceNames
);
1246 for (serviceIndex
= 0; serviceIndex
< servicesCount
; serviceIndex
++) {
1247 CFIndex configIndex
;
1248 CFIndex configsCount
;
1249 CFArrayRef serviceConfigs
;
1250 CFStringRef serviceName
;
1253 serviceName
= CFArrayGetValueAtIndex(serviceNames
, serviceIndex
);
1254 if (!isA_CFString(serviceName
))
1257 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1258 if (!isA_CFArray(serviceConfigs
))
1261 configsCount
= CFArrayGetCount(serviceConfigs
);
1262 for (configIndex
= 0; configIndex
< configsCount
; configIndex
++) {
1263 CFNumberRef autodial
;
1264 CFDictionaryRef config
;
1265 CFDictionaryRef pppConfig
;
1267 config
= CFArrayGetValueAtIndex(serviceConfigs
, configIndex
);
1268 if (!isA_CFDictionary(config
))
1271 pppConfig
= CFDictionaryGetValue(config
, kSCEntNetPPP
);
1272 if (!isA_CFDictionary(pppConfig
))
1275 autodial
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandEnabled
);
1276 if (!isA_CFNumber(autodial
))
1279 CFNumberGetValue(autodial
, kCFNumberIntType
, &val
);
1281 CFArrayRef autoDomains
;
1282 CFIndex domainIndex
;
1283 CFIndex domainsCount
;
1285 /* we found an conditional connection enabled configuration */
1288 autoDomains
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandDomains
);
1289 if (!isA_CFArray(autoDomains
))
1292 domainsCount
= CFArrayGetCount(autoDomains
);
1293 for (domainIndex
= 0; domainIndex
< domainsCount
; domainIndex
++) {
1296 domain
= CFArrayGetValueAtIndex(autoDomains
, domainIndex
);
1297 if (!isA_CFString(domain
))
1300 if (!catchAllFound
&&
1301 (CFStringCompare(domain
, CFSTR(""), 0) == kCFCompareEqualTo
1302 || CFStringCompare(domain
, CFSTR("."), 0) == kCFCompareEqualTo
)) {
1303 // found a catch all
1304 catchAllFound
= TRUE
;
1305 catchAllService
= serviceIndex
;
1306 catchAllConfig
= configIndex
;
1309 if (domainEndsWithDomain(hostName
, domain
)) {
1310 // found matching configuration
1311 *serviceID
= serviceName
;
1312 CFRetain(*serviceID
);
1313 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1314 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandHostName
, hostName
);
1315 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1316 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1318 goto done_selection
;
1325 // config not found, do we have a catchall ?
1326 if (catchAllFound
) {
1327 CFDictionaryRef config
;
1328 CFArrayRef serviceConfigs
;
1329 CFStringRef serviceName
;
1331 serviceName
= CFArrayGetValueAtIndex(serviceNames
, catchAllService
);
1332 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1333 config
= CFArrayGetValueAtIndex(serviceConfigs
, catchAllConfig
);
1335 *serviceID
= serviceName
;
1336 CFRetain(*serviceID
);
1337 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1338 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandHostName
, hostName
);
1339 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1340 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1342 goto done_selection
;
1348 CFRelease(serviceNames
);
1350 CFRelease(services
);
1354 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@"), success
? CFSTR("succeeded") : CFSTR("failed"));
1355 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Selection options: %@"), selectionOptions
);
1361 /* we don't have selection options */
1363 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
1364 success
= SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session
, serviceID
);
1366 if (success
&& (*serviceID
!= NULL
)) {
1367 // (2) Get the list of user data for this service ID
1368 CFPropertyListRef userServices
= NULL
;
1371 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
1372 if (userServices
!= NULL
) {
1373 if (isA_CFArray(userServices
)) {
1374 // (4) Get the default set of user options for this service
1375 success
= SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray((CFArrayRef
)userServices
,
1377 if(success
&& (userOptions
!= NULL
)) {
1378 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1381 fprintf(stderr
, "Error, userServices are not of type CFArray!\n");
1384 CFRelease(userServices
); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
1389 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@, no selection options"), success
? CFSTR("succeeded") : CFSTR("failed"));
1397 //*******************************************************************************************
1398 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
1399 // ----------------------------------------------------
1400 // Try to find the service id to connect
1401 // (1) Start by looking at the last service used in Internet Connect
1402 // (2) If Internet Connect has not been used, find the PPP service with the highest ordering
1403 //********************************************************************************************
1405 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1407 Boolean foundService
= FALSE
;
1408 CFPropertyListRef lastServiceSelectedInIC
= NULL
;
1412 // we found the service the user last had open in IC
1413 if (lastServiceSelectedInIC
!= NULL
) {
1414 // make sure its a PPP service
1415 if (SCNetworkConnectionPrivateIsPPPService(session
, lastServiceSelectedInIC
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1416 // make sure the service that we found is valid
1417 CFDictionaryRef dict
;
1420 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1421 kSCDynamicStoreDomainSetup
,
1422 lastServiceSelectedInIC
,
1423 kSCEntNetInterface
);
1424 dict
= SCDynamicStoreCopyValue(session
, key
);
1428 *serviceID
= CFRetain(lastServiceSelectedInIC
);
1429 foundService
= TRUE
;
1432 CFRelease(lastServiceSelectedInIC
);
1435 if (!foundService
) {
1436 foundService
= SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session
, serviceID
);
1439 return foundService
;
1442 //********************************************************************************
1443 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
1444 // -------------------------------------------------------
1445 // Find the highest ordered PPP service in the dynamic store
1446 //********************************************************************************
1448 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1450 CFDictionaryRef dict
= NULL
;
1451 CFStringRef key
= NULL
;
1452 CFArrayRef serviceIDs
= NULL
;
1453 Boolean success
= FALSE
;
1461 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCEntNetIPv4
);
1463 fprintf(stderr
, "Error, Setup Key == NULL!\n");
1467 dict
= SCDynamicStoreCopyValue(session
, key
);
1468 if (!isA_CFDictionary(dict
)) {
1469 fprintf(stderr
, "no global IPv4 entity\n");
1473 serviceIDs
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
); // array of service id's
1474 if (!isA_CFArray(serviceIDs
)) {
1475 fprintf(stderr
, "service order not specified\n");
1479 count
= CFArrayGetCount(serviceIDs
);
1480 for (i
= 0; i
< count
; i
++) {
1481 CFStringRef service
= CFArrayGetValueAtIndex(serviceIDs
, i
);
1483 if (SCNetworkConnectionPrivateIsPPPService(session
, service
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1484 *serviceID
= CFRetain(service
);
1491 if (key
!= NULL
) CFRelease(key
);
1492 if (dict
!= NULL
) CFRelease(dict
);
1497 //********************************************************************************
1498 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
1499 // ---------------------------------------------------------
1500 // Copy over user preferences for a particular service if they exist
1501 //********************************************************************************
1503 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
)
1505 CFIndex count
= CFArrayGetCount(userOptionsArray
);
1508 for (i
= 0; i
< count
; i
++) {
1509 // (1) Find the dictionary
1510 CFPropertyListRef propertyList
= CFArrayGetValueAtIndex(userOptionsArray
, i
);
1512 if (isA_CFDictionary(propertyList
) != NULL
) {
1513 // See if there's a value for dial on demand
1514 CFPropertyListRef value
;
1516 value
= CFDictionaryGetValue((CFDictionaryRef
)propertyList
, k_Dial_Default_Key
);
1517 if (isA_CFBoolean(value
) != NULL
) {
1518 if (CFBooleanGetValue(value
)) {
1519 // we found the default user options
1520 *userOptions
= CFDictionaryCreateCopy(NULL
,
1521 (CFDictionaryRef
)propertyList
);
1531 //********************************************************************************
1532 // SCNetworkConnectionPrivateIsServiceType
1533 // --------------------------------------
1534 // Check and see if the service is a PPP service of the given types
1535 //********************************************************************************
1537 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
)
1539 CFStringRef entityKey
;
1540 Boolean isPPPService
= FALSE
;
1541 Boolean isMatchingSubType
= FALSE
;
1542 CFDictionaryRef serviceDict
;
1544 entityKey
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1545 kSCDynamicStoreDomainSetup
,
1547 kSCEntNetInterface
);
1548 if (entityKey
== NULL
) {
1552 serviceDict
= SCDynamicStoreCopyValue(session
, entityKey
);
1553 if (serviceDict
!= NULL
) {
1554 if (isA_CFDictionary(serviceDict
)) {
1556 CFStringRef subtype
;
1558 type
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceType
);
1559 if (isA_CFString(type
)) {
1560 isPPPService
= CFEqual(type
, kSCValNetInterfaceTypePPP
);
1563 subtype
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceSubType
);
1564 if (isA_CFString(subtype
)) {
1565 isMatchingSubType
= CFEqual(subtype
, subType1
);
1566 if (!isMatchingSubType
&& subType2
)
1567 isMatchingSubType
= CFEqual(subtype
, subType2
);
1570 CFRelease(serviceDict
);
1572 CFRelease(entityKey
);
1574 return (isPPPService
&& isMatchingSubType
);
1577 //********************************************************************************
1578 // addPasswordFromKeychain
1579 // --------------------------------------
1580 // Get the password and shared secret out of the keychain and add
1581 // them to the PPP and IPSec dictionaries
1582 //********************************************************************************
1584 addPasswordFromKeychain(SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
)
1586 CFPropertyListRef uniqueID
;
1587 CFStringRef password
;
1588 CFStringRef sharedsecret
= NULL
;
1590 /* user options must exist */
1591 if (*userOptions
== NULL
)
1594 /* first, get the unique identifier used to store passwords in the keychain */
1595 uniqueID
= CFDictionaryGetValue(*userOptions
, k_Unique_Id_Key
);
1596 if (!isA_CFString(uniqueID
))
1599 /* first, get the PPP password */
1600 password
= copyPasswordFromKeychain(uniqueID
);
1602 /* then, if necessary, get the IPSec Shared Secret */
1603 if (SCNetworkConnectionPrivateIsPPPService(session
, serviceID
, kSCValNetInterfaceSubTypeL2TP
, 0)) {
1604 CFMutableStringRef uniqueIDSS
;
1606 uniqueIDSS
= CFStringCreateMutableCopy(NULL
, 0, uniqueID
);
1607 CFStringAppend(uniqueIDSS
, CFSTR(".SS"));
1608 sharedsecret
= copyPasswordFromKeychain(uniqueIDSS
);
1609 CFRelease(uniqueIDSS
);
1612 /* did we find our information in the key chain ? */
1613 if ((password
!= NULL
) || (sharedsecret
!= NULL
)) {
1614 CFMutableDictionaryRef newOptions
;
1616 newOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, *userOptions
);
1619 if (password
!= NULL
) {
1620 CFDictionaryRef entity
;
1621 CFMutableDictionaryRef newEntity
;
1623 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetPPP
);
1624 if (isA_CFDictionary(entity
))
1625 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1627 newEntity
= CFDictionaryCreateMutable(NULL
,
1629 &kCFTypeDictionaryKeyCallBacks
,
1630 &kCFTypeDictionaryValueCallBacks
);
1633 /* set the PPP password */
1634 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPassword
, uniqueID
);
1635 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPasswordEncryption
, kSCValNetPPPAuthPasswordEncryptionKeychain
);
1636 CFRelease(password
);
1638 /* update the PPP entity */
1639 CFDictionarySetValue(newOptions
, kSCEntNetPPP
, newEntity
);
1640 CFRelease(newEntity
);
1643 /* IPSec Shared Secret */
1644 if (sharedsecret
!= NULL
) {
1645 CFDictionaryRef entity
;
1646 CFMutableDictionaryRef newEntity
;
1648 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetIPSec
);
1649 if (isA_CFDictionary(entity
))
1650 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1652 newEntity
= CFDictionaryCreateMutable(NULL
,
1654 &kCFTypeDictionaryKeyCallBacks
,
1655 &kCFTypeDictionaryValueCallBacks
);
1657 /* set the IPSec Shared Secret */
1658 CFDictionarySetValue(newEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
1659 CFRelease(sharedsecret
);
1661 /* update the IPSec entity */
1662 CFDictionarySetValue(newOptions
, kSCEntNetIPSec
, newEntity
);
1663 CFRelease(newEntity
);
1666 /* update the userOptions dictionary */
1667 CFRelease(*userOptions
);
1668 *userOptions
= CFDictionaryCreateCopy(NULL
, newOptions
);
1669 CFRelease(newOptions
);
1674 //********************************************************************************
1675 // copyPasswordFromKeychain
1676 // --------------------------------------
1677 // Given a uniqueID, retrieve the password from the keychain
1678 //********************************************************************************
1680 copyPasswordFromKeychain(CFStringRef uniqueID
)
1682 CFArrayRef enumerator
;
1684 CFStringRef password
= NULL
;
1686 enumerator
= copyKeychainEnumerator(uniqueID
);
1687 if (enumerator
== NULL
) {
1688 return NULL
; // if no keychain enumerator
1691 n
= CFArrayGetCount(enumerator
);
1695 SecKeychainItemRef itemRef
;
1698 itemRef
= (SecKeychainItemRef
)CFArrayGetValueAtIndex(enumerator
, 0);
1699 result
= SecKeychainItemCopyContent(itemRef
, // itemRef
1703 (void *)&data
); // outData
1704 if ((result
== noErr
) && (data
!= NULL
) && (dataLen
> 0)) {
1705 password
= CFStringCreateWithBytes(NULL
, data
, dataLen
, kCFStringEncodingUTF8
, TRUE
);
1706 (void) SecKeychainItemFreeContent(NULL
, data
);
1711 CFRelease(enumerator
);
1716 //********************************************************************************
1717 // copyKeychainEnumerator
1718 // --------------------------------------
1719 // Gather Keychain Enumerator
1720 //********************************************************************************
1722 copyKeychainEnumerator(CFStringRef uniqueIdentifier
)
1725 CFMutableArrayRef itemArray
= NULL
;
1727 SecKeychainSearchRef search
= NULL
;
1729 buf
= _SC_cfstring_to_cstring(uniqueIdentifier
, NULL
, 0, kCFStringEncodingUTF8
);
1731 // search for unique identifier in "svce" attribute
1732 SecKeychainAttribute attributes
[] = {{ kSecServiceItemAttr
,
1733 CFStringGetLength(uniqueIdentifier
),
1737 SecKeychainAttributeList attrList
= { sizeof(attributes
) / sizeof(*attributes
),
1740 result
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attrList
, &search
);
1741 if (result
== noErr
) {
1742 itemArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1744 while (result
== noErr
) {
1745 SecKeychainItemRef itemFound
= NULL
;
1747 result
= SecKeychainSearchCopyNext(search
, &itemFound
);
1748 if (result
!= noErr
) {
1753 CFArrayAppendValue(itemArray
, itemFound
);
1754 CFRelease(itemFound
);
1760 if (search
) CFRelease(search
);
1761 if (buf
) CFAllocatorDeallocate(NULL
, buf
);