2 * Copyright (c) 2003-2009 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 <Availability.h>
36 #include <TargetConditionals.h>
37 #include <sys/cdefs.h>
39 #include <dispatch/dispatch.h>
40 #endif // !TARGET_OS_IPHONE
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <CoreFoundation/CFRuntime.h>
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h>
45 #include <SystemConfiguration/SCValidation.h>
48 #include <Security/Security.h>
49 #include "dy_framework.h"
50 #endif // !TARGET_OS_IPHONE
52 #include <servers/bootstrap.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
60 #include <sys/ioctl.h>
61 #include <sys/socket.h>
63 #include <mach/mach.h>
65 #include <ppp/ppp_msg.h>
66 #include "pppcontroller.h"
67 #include <ppp/pppcontroller_types.h>
72 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
77 /* base CFType information */
84 SCNetworkServiceRef service
;
86 /* ref to PPP controller for control messages */
87 mach_port_t session_port
;
89 /* ref to PPP controller for notification messages */
90 CFMachPortRef notify_port
;
92 /* run loop source, callout, context, rl scheduling info */
94 CFRunLoopSourceRef rls
;
95 SCNetworkConnectionCallBack rlsFunction
;
96 SCNetworkConnectionContext rlsContext
;
97 CFMutableArrayRef rlList
;
100 dispatch_queue_t dispatchQueue
; // SCNetworkConnectionSetDispatchQueue
101 dispatch_queue_t callbackQueue
;
102 dispatch_source_t callbackSource
;
103 #endif // !TARGET_OS_IPHONE
105 } SCNetworkConnectionPrivate
, *SCNetworkConnectionPrivateRef
;
108 static __inline__ CFTypeRef
109 isA_SCNetworkConnection(CFTypeRef obj
)
111 return (isA_CFType(obj
, SCNetworkConnectionGetTypeID()));
116 __SCNetworkConnectionCopyDescription(CFTypeRef cf
)
118 CFAllocatorRef allocator
= CFGetAllocator(cf
);
119 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
120 CFMutableStringRef result
;
122 result
= CFStringCreateMutable(allocator
, 0);
123 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkConnection, %p [%p]> {"), cf
, allocator
);
124 CFStringAppendFormat(result
, NULL
, CFSTR("service = %p"), connectionPrivate
->service
);
125 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
) {
126 CFStringAppendFormat(result
, NULL
, CFSTR(", server port = %p"), connectionPrivate
->session_port
);
128 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
135 __SCNetworkConnectionDeallocate(CFTypeRef cf
)
137 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
139 /* release resources */
140 pthread_mutex_destroy(&connectionPrivate
->lock
);
142 if (connectionPrivate
->rls
!= NULL
) {
143 CFRunLoopSourceInvalidate(connectionPrivate
->rls
);
144 CFRelease(connectionPrivate
->rls
);
147 if (connectionPrivate
->rlList
!= NULL
) {
148 CFRelease(connectionPrivate
->rlList
);
151 if (connectionPrivate
->notify_port
!= NULL
) {
152 mach_port_t mp
= CFMachPortGetPort(connectionPrivate
->notify_port
);
154 __MACH_PORT_DEBUG(TRUE
, "*** __SCNetworkConnectionDeallocate notify_port", mp
);
155 CFMachPortInvalidate(connectionPrivate
->notify_port
);
156 CFRelease(connectionPrivate
->notify_port
);
157 mach_port_mod_refs(mach_task_self(), mp
, MACH_PORT_RIGHT_RECEIVE
, -1);
160 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
) {
161 __MACH_PORT_DEBUG(TRUE
, "*** __SCNetworkConnectionDeallocate session_port", connectionPrivate
->session_port
);
162 (void) mach_port_deallocate(mach_task_self(), connectionPrivate
->session_port
);
165 if (connectionPrivate
->rlsContext
.release
!= NULL
)
166 (*connectionPrivate
->rlsContext
.release
)(connectionPrivate
->rlsContext
.info
);
168 CFRelease(connectionPrivate
->service
);
174 static CFTypeID __kSCNetworkConnectionTypeID
= _kCFRuntimeNotATypeID
;
176 static const CFRuntimeClass __SCNetworkConnectionClass
= {
178 "SCNetworkConnection", // className
181 __SCNetworkConnectionDeallocate
, // dealloc
184 NULL
, // copyFormattingDesc
185 __SCNetworkConnectionCopyDescription
// copyDebugDesc
190 __SCNetworkConnectionInitialize(void)
194 /* get the debug environment variable */
195 env
= getenv("PPPDebug");
197 if (sscanf(env
, "%d", &debug
) != 1) {
198 /* PPPDebug value is not valid (or non-numeric), set debug to 1 */
203 __kSCNetworkConnectionTypeID
= _CFRuntimeRegisterClass(&__SCNetworkConnectionClass
);
209 __SCNetworkConnectionCallBack(CFMachPortRef port
, void * msg
, CFIndex size
, void * info
)
211 mach_msg_empty_rcv_t
* buf
= msg
;
212 SCNetworkConnectionRef connection
= (SCNetworkConnectionRef
)info
;
213 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
215 void (*context_release
)(const void *);
216 int error
= kSCStatusFailed
;
217 mach_msg_id_t msgid
= buf
->header
.msgh_id
;
218 SCNetworkConnectionCallBack rlsFunction
;
219 SCNetworkConnectionStatus scstatus
= kSCNetworkConnectionInvalid
;
221 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
222 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionCallBack: PPPController server died"));
224 (void) pppcontroller_getstatus(connectionPrivate
->session_port
, &scstatus
, &error
);
227 if (!connectionPrivate
->scheduled
) {
228 // if not currently scheduled
232 rlsFunction
= connectionPrivate
->rlsFunction
;
233 if (rlsFunction
== NULL
) {
237 if ((connectionPrivate
->rlsContext
.retain
!= NULL
) && (connectionPrivate
->rlsContext
.info
!= NULL
)) {
238 context_info
= (void *)(*connectionPrivate
->rlsContext
.retain
)(connectionPrivate
->rlsContext
.info
);
239 context_release
= connectionPrivate
->rlsContext
.release
;
241 context_info
= connectionPrivate
->rlsContext
.info
;
242 context_release
= NULL
;
245 (*rlsFunction
)(connection
, scstatus
, context_info
);
246 if ((context_release
!= NULL
) && (context_info
!= NULL
)) {
247 (*context_release
)(context_info
);
255 #pragma mark SCNetworkConnection APIs
259 pppMPCopyDescription(const void *info
)
261 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)info
;
263 return CFStringCreateWithFormat(NULL
,
265 CFSTR("<SCNetworkConnection MP %p> {service = %@, callout = %p}"),
267 connectionPrivate
->service
,
268 connectionPrivate
->rlsFunction
);
272 static SCNetworkConnectionPrivateRef
273 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator
,
274 SCNetworkServiceRef service
,
275 SCNetworkConnectionCallBack callout
,
276 SCNetworkConnectionContext
*context
)
278 SCNetworkConnectionPrivateRef connectionPrivate
= NULL
;
282 /* initialize runtime */
283 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
285 /* allocate NetworkConnection */
286 size
= sizeof(SCNetworkConnectionPrivate
) - sizeof(CFRuntimeBase
);
287 connectionPrivate
= (SCNetworkConnectionPrivateRef
)_CFRuntimeCreateInstance(allocator
, __kSCNetworkConnectionTypeID
, size
, NULL
);
288 if (connectionPrivate
== NULL
) {
292 /* zero the data structure */
293 bzero(((u_char
*)connectionPrivate
)+sizeof(CFRuntimeBase
), size
);
295 pthread_mutex_init(&connectionPrivate
->lock
, NULL
);
297 /* save the service */
298 connectionPrivate
->service
= CFRetain(service
);
300 connectionPrivate
->rlsFunction
= callout
;
303 bcopy(context
, &connectionPrivate
->rlsContext
, sizeof(SCNetworkConnectionContext
));
304 if (context
->retain
!= NULL
) {
305 connectionPrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
309 /* success, return the connection reference */
310 return connectionPrivate
;
314 /* failure, clean up and leave */
315 if (connectionPrivate
!= NULL
) {
316 CFRelease(connectionPrivate
);
319 _SCErrorSet(kSCStatusFailed
);
325 __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate
)
329 CFDataRef dataRef
= NULL
;
330 int error
= kSCStatusFailed
;
331 mach_port_t notify_port
= MACH_PORT_NULL
;
332 mach_port_t oldNotify
= MACH_PORT_NULL
;
333 mach_port_t server
= MACH_PORT_NULL
;
334 kern_return_t status
;
335 mach_port_t unpriv_bootstrap_port
= MACH_PORT_NULL
;
337 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
) {
338 return connectionPrivate
->session_port
;
341 pthread_mutex_lock(&connectionPrivate
->lock
);
343 if (bootstrap_look_up(bootstrap_port
, PPPCONTROLLER_SERVER
, &server
) != BOOTSTRAP_SUCCESS
) {
344 SCLog(_sc_verbose
, LOG_ERR
, CFSTR("PPP Controller not found"));
348 if (!_SCSerializeString(SCNetworkServiceGetServiceID(connectionPrivate
->service
), &dataRef
, &data
, &dataLen
)) {
352 status
= bootstrap_unprivileged(bootstrap_port
, &unpriv_bootstrap_port
);
353 if (status
!= BOOTSTRAP_SUCCESS
) {
357 if (connectionPrivate
->rlsFunction
!= NULL
) {
358 /* allocate port (for server response) */
359 status
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, ¬ify_port
);
360 if (status
!= KERN_SUCCESS
) {
364 status
= mach_port_insert_right(mach_task_self(),
367 MACH_MSG_TYPE_MAKE_SEND
);
368 if (status
!= KERN_SUCCESS
) {
370 * We can't insert a send right into our own port! This should
371 * only happen if someone stomped on OUR port (so let's leave
374 SCLog(TRUE
, LOG_ERR
, CFSTR("__SCNetworkConnectionSessionPort mach_port_insert_right(): %s"), mach_error_string(status
));
378 /* request a notification when/if the server dies */
379 status
= mach_port_request_notification(mach_task_self(),
381 MACH_NOTIFY_NO_SENDERS
,
384 MACH_MSG_TYPE_MAKE_SEND_ONCE
,
386 if (status
!= KERN_SUCCESS
) {
390 if (oldNotify
!= MACH_PORT_NULL
) {
391 SCLog(TRUE
, LOG_ERR
, CFSTR("__SCNetworkConnectionSessionPort(): oldNotify != MACH_PORT_NULL"));
394 __MACH_PORT_DEBUG(TRUE
, "*** __SCNetworkConnectionSessionPort notify_port (before)", notify_port
);
397 status
= pppcontroller_attach(server
, data
, dataLen
, unpriv_bootstrap_port
, notify_port
,
398 &connectionPrivate
->session_port
, &error
);
399 if (status
!= KERN_SUCCESS
) {
400 SCLog(TRUE
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionSessionPort : pppcontroller_attach failed (status=0x%x)"), status
);
401 if ((notify_port
!= MACH_PORT_NULL
) && (status
== MACH_SEND_INVALID_DEST
)) {
402 (void) mach_port_destroy(mach_task_self(), notify_port
);
403 notify_port
= MACH_PORT_NULL
;
405 error
= kSCStatusFailed
;
409 __MACH_PORT_DEBUG(connectionPrivate
->session_port
!= MACH_PORT_NULL
,
410 "*** __SCNetworkConnectionSessionPort session_port",
411 connectionPrivate
->session_port
);
412 __MACH_PORT_DEBUG(notify_port
!= MACH_PORT_NULL
,
413 "*** __SCNetworkConnectionSessionPort notify_port",
416 if (notify_port
!= MACH_PORT_NULL
) {
417 CFMachPortContext context
= { 0
418 , (void *)connectionPrivate
421 , pppMPCopyDescription
424 connectionPrivate
->notify_port
= CFMachPortCreateWithPort(NULL
, notify_port
, __SCNetworkConnectionCallBack
, &context
, NULL
);
429 if (dataRef
!= NULL
) CFRelease(dataRef
);
431 if (unpriv_bootstrap_port
!= MACH_PORT_NULL
) {
432 mach_port_deallocate(mach_task_self(), unpriv_bootstrap_port
);
435 if (error
!= kSCStatusOK
) {
436 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
) {
437 __MACH_PORT_DEBUG(TRUE
,
438 "*** __SCNetworkConnectionSessionPort attach failed: session_port",
439 connectionPrivate
->session_port
);
440 mach_port_deallocate(mach_task_self(), connectionPrivate
->session_port
);
441 connectionPrivate
->session_port
= MACH_PORT_NULL
;
443 if (connectionPrivate
->notify_port
!= NULL
) {
444 mach_port_t port
= CFMachPortGetPort(connectionPrivate
->notify_port
);
446 CFMachPortInvalidate(connectionPrivate
->notify_port
);
447 CFRelease(connectionPrivate
->notify_port
);
448 connectionPrivate
->notify_port
= NULL
;
449 __MACH_PORT_DEBUG(TRUE
, "*** __SCNetworkConnectionSessionPort attach failed: notify_port", port
);
450 mach_port_mod_refs(mach_task_self(), port
, MACH_PORT_RIGHT_RECEIVE
, -1);
455 pthread_mutex_unlock(&connectionPrivate
->lock
);
457 return connectionPrivate
->session_port
;
462 SCNetworkConnectionGetTypeID(void) {
463 pthread_once(&initialized
, __SCNetworkConnectionInitialize
); /* initialize runtime */
464 return __kSCNetworkConnectionTypeID
;
468 CFArrayRef
/* of SCNetworkServiceRef's */
469 SCNetworkConnectionCopyAvailableServices(SCNetworkSetRef set
)
471 CFMutableArrayRef available
;
472 Boolean tempSet
= FALSE
;
475 SCPreferencesRef prefs
;
477 prefs
= SCPreferencesCreate(NULL
, CFSTR("SCNetworkConnectionCopyAvailableServices"), NULL
);
479 set
= SCNetworkSetCopyCurrent(prefs
);
485 available
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
490 services
= SCNetworkSetCopyServices(set
);
491 if (services
!= NULL
) {
495 n
= CFArrayGetCount(services
);
496 for (i
= 0; i
< n
; i
++) {
497 SCNetworkInterfaceRef interface
;
498 CFStringRef interfaceType
;
499 SCNetworkServiceRef service
;
501 service
= CFArrayGetValueAtIndex(services
, i
);
502 interface
= SCNetworkServiceGetInterface(service
);
503 if (interface
== NULL
) {
507 interfaceType
= SCNetworkInterfaceGetInterfaceType(interface
);
508 if (CFEqual(interfaceType
, kSCNetworkInterfaceTypePPP
) ||
509 CFEqual(interfaceType
, kSCNetworkInterfaceTypeIPSec
)) {
510 CFArrayAppendValue(available
, service
);
518 if (tempSet
&& (set
!= NULL
)) {
525 SCNetworkConnectionRef
526 SCNetworkConnectionCreateWithService(CFAllocatorRef allocator
,
527 SCNetworkServiceRef service
,
528 SCNetworkConnectionCallBack callout
,
529 SCNetworkConnectionContext
*context
)
531 SCNetworkConnectionPrivateRef connectionPrivate
;
533 if (!isA_SCNetworkService(service
)) {
534 _SCErrorSet(kSCStatusInvalidArgument
);
538 connectionPrivate
= __SCNetworkConnectionCreatePrivate(allocator
, service
, callout
, context
);
539 return (SCNetworkConnectionRef
)connectionPrivate
;
543 SCNetworkConnectionRef
544 SCNetworkConnectionCreateWithServiceID(CFAllocatorRef allocator
,
545 CFStringRef serviceID
,
546 SCNetworkConnectionCallBack callout
,
547 SCNetworkConnectionContext
*context
)
549 SCNetworkConnectionRef connection
;
550 SCNetworkServiceRef service
;
552 if (!isA_CFString(serviceID
)) {
553 _SCErrorSet(kSCStatusInvalidArgument
);
557 service
= _SCNetworkServiceCopyActive(NULL
, serviceID
);
558 if (service
== NULL
) {
562 connection
= SCNetworkConnectionCreateWithService(allocator
, service
, callout
, context
);
570 SCNetworkConnectionCopyServiceID(SCNetworkConnectionRef connection
)
572 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
573 CFStringRef serviceID
;
575 if (!isA_SCNetworkConnection(connection
)) {
576 _SCErrorSet(kSCStatusInvalidArgument
);
580 serviceID
= SCNetworkServiceGetServiceID(connectionPrivate
->service
);
581 return CFRetain(serviceID
);
586 SCNetworkConnectionCopyStatistics(SCNetworkConnectionRef connection
)
588 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
589 xmlDataOut_t data
= NULL
;
590 mach_msg_type_number_t datalen
;
591 int error
= kSCStatusFailed
;
592 mach_port_t session_port
;
593 CFPropertyListRef statistics
= NULL
;
594 kern_return_t status
;
596 if (!isA_SCNetworkConnection(connection
)) {
597 _SCErrorSet(kSCStatusInvalidArgument
);
601 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
602 if (session_port
== MACH_PORT_NULL
) {
603 _SCErrorSet(kSCStatusInvalidArgument
);
607 status
= pppcontroller_copystatistics(session_port
, &data
, &datalen
, &error
);
608 if (status
!= KERN_SUCCESS
) {
612 if (error
!= kSCStatusOK
) {
616 if ((data
== NULL
) ||
617 !_SCUnserialize(&statistics
, NULL
, data
, datalen
) ||
618 !isA_CFDictionary(statistics
)) {
626 if (statistics
) CFRelease(statistics
);
633 SCNetworkConnectionGetService(SCNetworkConnectionRef connection
)
635 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
637 if (!isA_SCNetworkConnection(connection
)) {
638 _SCErrorSet(kSCStatusInvalidArgument
);
642 return connectionPrivate
->service
;
646 SCNetworkConnectionStatus
647 SCNetworkConnectionGetStatus(SCNetworkConnectionRef connection
)
649 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
650 int error
= kSCStatusFailed
;
651 SCNetworkConnectionStatus scstatus
;
652 mach_port_t session_port
;
653 kern_return_t status
;
655 if (!isA_SCNetworkConnection(connection
)) {
656 _SCErrorSet(kSCStatusInvalidArgument
);
657 return kSCNetworkConnectionInvalid
;
660 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
661 if (session_port
== MACH_PORT_NULL
) {
662 _SCErrorSet(kSCStatusInvalidArgument
);
663 return kSCNetworkConnectionInvalid
;
666 status
= pppcontroller_getstatus(session_port
, &scstatus
, &error
);
667 if (status
!= KERN_SUCCESS
) {
668 _SCErrorSet(kSCStatusFailed
);
669 return kSCNetworkConnectionInvalid
;
672 if (error
!= kSCStatusOK
) {
674 return kSCNetworkConnectionInvalid
;
682 SCNetworkConnectionCopyExtendedStatus(SCNetworkConnectionRef connection
)
684 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
685 xmlDataOut_t data
= NULL
;
686 mach_msg_type_number_t datalen
;
687 int error
= kSCStatusFailed
;
688 CFPropertyListRef extstatus
= NULL
;
689 mach_port_t session_port
;
690 kern_return_t status
;
692 if (!isA_SCNetworkConnection(connection
)) {
693 _SCErrorSet(kSCStatusInvalidArgument
);
697 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
698 if (session_port
== MACH_PORT_NULL
) {
699 _SCErrorSet(kSCStatusInvalidArgument
);
703 status
= pppcontroller_copyextendedstatus(session_port
, &data
, &datalen
, &error
);
704 if (status
!= KERN_SUCCESS
) {
708 if (error
!= kSCStatusOK
) {
712 if ((data
== NULL
) ||
713 !_SCUnserialize(&extstatus
, NULL
, data
, datalen
) ||
714 !isA_CFDictionary(extstatus
)) {
722 if (extstatus
) CFRelease(extstatus
);
729 SCNetworkConnectionStart(SCNetworkConnectionRef connection
,
730 CFDictionaryRef userOptions
,
733 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
734 CFDataRef dataref
= NULL
;
737 int error
= kSCStatusFailed
;
738 mach_port_t session_port
;
739 kern_return_t status
;
741 if (!isA_SCNetworkConnection(connection
)) {
742 _SCErrorSet(kSCStatusInvalidArgument
);
746 if ((userOptions
!= NULL
) && !isA_CFDictionary(userOptions
)) {
747 _SCErrorSet(kSCStatusInvalidArgument
);
751 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
752 if (session_port
== MACH_PORT_NULL
) {
753 _SCErrorSet(kSCStatusInvalidArgument
);
758 CFMutableDictionaryRef mdict
= NULL
;
760 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x)"), connectionPrivate
);
762 if (userOptions
!= NULL
) {
763 CFDictionaryRef dict
;
764 CFStringRef encryption
;
765 CFMutableDictionaryRef new_dict
;
767 /* special code to remove secret information */
768 mdict
= CFDictionaryCreateMutableCopy(NULL
, 0, userOptions
);
770 dict
= CFDictionaryGetValue(mdict
, kSCEntNetPPP
);
771 if (isA_CFDictionary(dict
)) {
772 encryption
= CFDictionaryGetValue(dict
, kSCPropNetPPPAuthPasswordEncryption
);
773 if (!isA_CFString(encryption
) ||
774 !CFEqual(encryption
, kSCValNetPPPAuthPasswordEncryptionKeychain
)) {
775 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
776 CFDictionaryReplaceValue(new_dict
, kSCPropNetPPPAuthPassword
, CFSTR("******"));
777 CFDictionarySetValue(mdict
, kSCEntNetPPP
, new_dict
);
782 dict
= CFDictionaryGetValue(mdict
, kSCEntNetL2TP
);
783 if (isA_CFDictionary(dict
)) {
784 encryption
= CFDictionaryGetValue(dict
, kSCPropNetL2TPIPSecSharedSecretEncryption
);
785 if (!isA_CFString(encryption
) ||
786 !CFEqual(encryption
, kSCValNetL2TPIPSecSharedSecretEncryptionKeychain
)) {
787 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
788 CFDictionaryReplaceValue(new_dict
, kSCPropNetL2TPIPSecSharedSecret
, CFSTR("******"));
789 CFDictionarySetValue(mdict
, kSCEntNetL2TP
, new_dict
);
794 dict
= CFDictionaryGetValue(mdict
, kSCEntNetIPSec
);
795 if (isA_CFDictionary(dict
)) {
796 encryption
= CFDictionaryGetValue(dict
, kSCPropNetIPSecSharedSecretEncryption
);
797 if (!isA_CFString(encryption
) ||
798 !CFEqual(encryption
, kSCValNetIPSecSharedSecretEncryptionKeychain
)) {
799 new_dict
= CFDictionaryCreateMutableCopy(NULL
, 0, dict
);
800 CFDictionaryReplaceValue(new_dict
, kSCPropNetIPSecSharedSecret
, CFSTR("******"));
801 CFDictionarySetValue(mdict
, kSCEntNetIPSec
, new_dict
);
807 SCLog(TRUE
, LOG_DEBUG
, CFSTR("User options: %@"), mdict
);
808 if (mdict
!= NULL
) CFRelease(mdict
);
811 if (userOptions
&& !_SCSerialize(userOptions
, &dataref
, &data
, &datalen
)) {
815 status
= pppcontroller_start(session_port
, data
, datalen
, linger
, &error
);
816 if (status
!= KERN_SUCCESS
) {
826 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x), return: %d"), connectionPrivate
, error
);
829 if (error
!= kSCStatusOK
) {
833 /* connection is now started */
838 if (dataref
) CFRelease(dataref
);
845 SCNetworkConnectionStop(SCNetworkConnectionRef connection
,
846 Boolean forceDisconnect
)
848 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
849 int error
= kSCStatusFailed
;
850 mach_port_t session_port
;
851 kern_return_t status
;
853 if (!isA_SCNetworkConnection(connection
)) {
854 _SCErrorSet(kSCStatusInvalidArgument
);
858 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
859 if (session_port
== MACH_PORT_NULL
) {
860 _SCErrorSet(kSCStatusInvalidArgument
);
865 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x)"), connectionPrivate
);
868 status
= pppcontroller_stop(session_port
, forceDisconnect
, &error
);
869 if (status
!= KERN_SUCCESS
) {
874 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x), return: %d"), connectionPrivate
, error
);
877 if (error
!= kSCStatusOK
) {
881 /* connection is now disconnecting */
892 SCNetworkConnectionSuspend(SCNetworkConnectionRef connection
)
894 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
895 int error
= kSCStatusFailed
;
896 mach_port_t session_port
;
897 kern_return_t status
;
899 if (!isA_SCNetworkConnection(connection
)) {
900 _SCErrorSet(kSCStatusInvalidArgument
);
904 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
905 if (session_port
== MACH_PORT_NULL
) {
906 _SCErrorSet(kSCStatusInvalidArgument
);
911 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x)"), connectionPrivate
);
914 status
= pppcontroller_suspend(session_port
, &error
);
915 if (status
!= KERN_SUCCESS
) {
920 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x), return: %d"), connectionPrivate
, error
);
923 if (error
!= kSCStatusOK
) {
927 /* connection is now suspended */
938 SCNetworkConnectionResume(SCNetworkConnectionRef connection
)
940 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
941 int error
= kSCStatusFailed
;
942 mach_port_t session_port
;
943 kern_return_t status
;
945 if (!isA_SCNetworkConnection(connection
)) {
946 _SCErrorSet(kSCStatusInvalidArgument
);
950 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
951 if (session_port
== MACH_PORT_NULL
) {
952 _SCErrorSet(kSCStatusInvalidArgument
);
957 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x)"), connectionPrivate
);
960 status
= pppcontroller_resume(session_port
, &error
);
961 if (status
!= KERN_SUCCESS
) {
966 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x), return: %d"), connectionPrivate
, error
);
969 if (error
!= kSCStatusOK
) {
973 /* connection is now resume */
984 SCNetworkConnectionCopyUserOptions(SCNetworkConnectionRef connection
)
986 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
987 xmlDataOut_t data
= NULL
;
988 mach_msg_type_number_t datalen
;
989 int error
= kSCStatusFailed
;
990 mach_port_t session_port
;
991 kern_return_t status
;
992 CFPropertyListRef userOptions
= NULL
;
994 if (!isA_SCNetworkConnection(connection
)) {
995 _SCErrorSet(kSCStatusInvalidArgument
);
999 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
1000 if (session_port
== MACH_PORT_NULL
) {
1001 _SCErrorSet(kSCStatusInvalidArgument
);
1005 status
= pppcontroller_copyuseroptions(session_port
, &data
, &datalen
, &error
);
1006 if (status
!= KERN_SUCCESS
) {
1010 if (error
!= kSCStatusOK
) {
1014 // no data were used, return an empty dictionary
1016 CFDictionaryRef dict
;
1018 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1020 _SCErrorSet(kSCStatusFailed
); // XXX
1025 if (!_SCUnserialize(&userOptions
, NULL
, data
, datalen
) ||
1026 !isA_CFDictionary(userOptions
)) {
1034 if (userOptions
) CFRelease(userOptions
);
1040 #if !TARGET_OS_IPHONE
1042 SCNetworkConnectionNotifyMIGCallback(mach_msg_header_t
*message
, mach_msg_header_t
*reply
)
1044 SCNetworkConnectionPrivateRef connectionPrivate
= dispatch_get_context(dispatch_get_current_queue());
1046 if (connectionPrivate
!= NULL
) {
1047 CFRetain(connectionPrivate
);
1048 dispatch_async(connectionPrivate
->dispatchQueue
, ^{
1049 __SCNetworkConnectionCallBack(connectionPrivate
->notify_port
, message
, 4096, connectionPrivate
);
1050 CFRelease(connectionPrivate
);
1053 reply
->msgh_remote_port
= MACH_PORT_NULL
;
1056 #endif // !TARGET_OS_IPHONE
1060 __SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
1061 CFRunLoopRef runLoop
,
1062 CFStringRef runLoopMode
,
1063 #if !TARGET_OS_IPHONE
1064 dispatch_queue_t queue
1065 #else // !TARGET_OS_IPHONE
1067 #endif // !TARGET_OS_IPHONE
1070 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
1071 int error
= kSCStatusFailed
;
1072 mach_port_t session_port
;
1073 kern_return_t status
;
1075 if (connectionPrivate
->rlsFunction
== NULL
) {
1076 _SCErrorSet(kSCStatusInvalidArgument
);
1080 #if !TARGET_OS_IPHONE
1081 if ((connectionPrivate
->dispatchQueue
!= NULL
) || // if we are already scheduled on a dispatch queue
1082 ((queue
!= NULL
) && connectionPrivate
->scheduled
)) { // if we are already scheduled on a CFRunLoop
1083 _SCErrorSet(kSCStatusInvalidArgument
);
1086 #endif // !TARGET_OS_IPHONE
1088 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
1089 if (session_port
== MACH_PORT_NULL
) {
1090 _SCErrorSet(kSCStatusInvalidArgument
);
1094 if (!connectionPrivate
->scheduled
) {
1095 status
= pppcontroller_notification(session_port
, 1, &error
);
1096 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
1101 if (runLoop
!= NULL
) {
1102 connectionPrivate
->rls
= CFMachPortCreateRunLoopSource(NULL
, connectionPrivate
->notify_port
, 0);
1103 connectionPrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1106 connectionPrivate
->scheduled
= TRUE
;
1109 #if !TARGET_OS_IPHONE
1110 if (queue
!= NULL
) {
1113 connectionPrivate
->dispatchQueue
= queue
;
1114 dispatch_retain(connectionPrivate
->dispatchQueue
);
1116 connectionPrivate
->callbackQueue
= dispatch_queue_create("com.apple.SCNetworkConnection.notifications", NULL
);
1117 if (connectionPrivate
->callbackQueue
== NULL
){
1118 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkConnection dispatch_queue_create() failed"));
1121 CFRetain(connection
); // Note: will be released when the dispatch queue is released
1122 dispatch_set_context(connectionPrivate
->callbackQueue
, connectionPrivate
);
1123 dispatch_set_finalizer_f(connectionPrivate
->callbackQueue
, (dispatch_function_t
)CFRelease
);
1125 mp
= CFMachPortGetPort(connectionPrivate
->notify_port
);
1126 connectionPrivate
->callbackSource
= dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV
,
1129 connectionPrivate
->callbackQueue
);
1130 if (connectionPrivate
->callbackSource
== NULL
) {
1131 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkConnection dispatch_source_create() failed"));
1134 dispatch_source_set_event_handler(connectionPrivate
->callbackSource
, ^{
1135 dispatch_mig_server(connectionPrivate
->callbackSource
,
1136 sizeof(mach_msg_header_t
),
1137 SCNetworkConnectionNotifyMIGCallback
);
1139 dispatch_resume(connectionPrivate
->callbackSource
);
1141 #endif // !TARGET_OS_IPHONE
1143 if (!_SC_isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
1145 * if we do not already have notifications scheduled with
1146 * this runLoop / runLoopMode
1148 CFRunLoopAddSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
1151 _SC_schedule(connection
, runLoop
, runLoopMode
, connectionPrivate
->rlList
);
1156 #if !TARGET_OS_IPHONE
1159 if (connectionPrivate
->callbackSource
!= NULL
) {
1160 dispatch_source_cancel(connectionPrivate
->callbackSource
);
1161 dispatch_release(connectionPrivate
->callbackSource
);
1162 connectionPrivate
->callbackSource
= NULL
;
1164 if (connectionPrivate
->callbackQueue
!= NULL
) {
1165 dispatch_release(connectionPrivate
->callbackQueue
);
1166 connectionPrivate
->callbackQueue
= NULL
;
1168 if (connectionPrivate
->dispatchQueue
!= NULL
) {
1169 dispatch_release(connectionPrivate
->dispatchQueue
);
1170 connectionPrivate
->dispatchQueue
= NULL
;
1172 _SCErrorSet(kSCStatusFailed
);
1174 #endif // !TARGET_OS_IPHONE
1179 __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
1180 CFRunLoopRef runLoop
,
1181 CFStringRef runLoopMode
,
1182 #if !TARGET_OS_IPHONE
1183 dispatch_queue_t queue
1184 #else // !TARGET_OS_IPHONE
1186 #endif // !TARGET_OS_IPHONE
1189 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
1190 int error
= kSCStatusFailed
;
1192 mach_port_t session_port
;
1193 kern_return_t status
;
1195 if ((runLoop
!= NULL
) && !connectionPrivate
->scheduled
) { // if we should be scheduled (but are not)
1196 _SCErrorSet(kSCStatusInvalidArgument
);
1200 #if !TARGET_OS_IPHONE
1201 if (((runLoop
== NULL
) && (connectionPrivate
->dispatchQueue
== NULL
)) || // if we should be scheduled on a dispatch queue (but are not)
1202 ((runLoop
!= NULL
) && (connectionPrivate
->dispatchQueue
!= NULL
))) { // if we should be scheduled on a CFRunLoop (but are scheduled on a dispatch queue)
1203 _SCErrorSet(kSCStatusInvalidArgument
);
1206 #endif // !TARGET_OS_IPHONE
1208 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
1209 if (session_port
== MACH_PORT_NULL
) {
1210 _SCErrorSet(kSCStatusInvalidArgument
);
1214 #if !TARGET_OS_IPHONE
1215 if (runLoop
== NULL
) {
1216 dispatch_source_cancel(connectionPrivate
->callbackSource
);
1217 if (connectionPrivate
->callbackQueue
!= dispatch_get_current_queue()) {
1218 // ensure the cancellation has completed
1219 dispatch_sync(connectionPrivate
->callbackQueue
, ^{});
1221 dispatch_release(connectionPrivate
->callbackSource
);
1222 connectionPrivate
->callbackSource
= NULL
;
1223 dispatch_release(connectionPrivate
->callbackQueue
);
1224 connectionPrivate
->callbackQueue
= NULL
;
1225 dispatch_release(connectionPrivate
->dispatchQueue
);
1226 connectionPrivate
->dispatchQueue
= NULL
;
1228 #endif // !TARGET_OS_IPHONE
1230 if (!_SC_unschedule(connection
, runLoop
, runLoopMode
, connectionPrivate
->rlList
, FALSE
)) {
1231 // if not currently scheduled on this runLoop / runLoopMode
1232 _SCErrorSet(kSCStatusFailed
);
1236 n
= CFArrayGetCount(connectionPrivate
->rlList
);
1237 if (n
== 0 || !_SC_isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
1239 * if we are no longer scheduled to receive notifications for
1240 * this runLoop / runLoopMode
1242 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
1245 // if *all* notifications have been unscheduled
1246 CFRelease(connectionPrivate
->rlList
);
1247 connectionPrivate
->rlList
= NULL
;
1248 CFRunLoopSourceInvalidate(connectionPrivate
->rls
);
1249 CFRelease(connectionPrivate
->rls
);
1250 connectionPrivate
->rls
= NULL
;
1256 // if *all* notifications have been unscheduled
1257 connectionPrivate
->scheduled
= FALSE
;
1259 status
= pppcontroller_notification(session_port
, 0, &error
);
1260 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
1271 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
1272 CFRunLoopRef runLoop
,
1273 CFStringRef runLoopMode
)
1275 if (!isA_SCNetworkConnection(connection
) || (runLoop
== NULL
) || (runLoopMode
== NULL
)) {
1276 _SCErrorSet(kSCStatusInvalidArgument
);
1280 return __SCNetworkConnectionScheduleWithRunLoop(connection
, runLoop
, runLoopMode
, NULL
);
1285 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
1286 CFRunLoopRef runLoop
,
1287 CFStringRef runLoopMode
)
1289 if (!isA_SCNetworkConnection(connection
) || (runLoop
== NULL
) || (runLoopMode
== NULL
)) {
1290 _SCErrorSet(kSCStatusInvalidArgument
);
1294 return __SCNetworkConnectionUnscheduleFromRunLoop(connection
, runLoop
, runLoopMode
, NULL
);
1298 #if !TARGET_OS_IPHONE
1300 SCNetworkConnectionSetDispatchQueue(SCNetworkConnectionRef connection
,
1301 dispatch_queue_t queue
)
1305 if (!isA_SCNetworkConnection(connection
)) {
1306 _SCErrorSet(kSCStatusInvalidArgument
);
1310 if (queue
!= NULL
) {
1311 ok
= __SCNetworkConnectionScheduleWithRunLoop(connection
, NULL
, NULL
, queue
);
1313 ok
= __SCNetworkConnectionUnscheduleFromRunLoop(connection
, NULL
, NULL
, NULL
);
1318 #endif // !TARGET_OS_IPHONE
1322 #pragma mark User level "dial" API
1325 #define k_NetworkConnect_Notification "com.apple.networkConnect"
1326 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
1327 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
1329 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
1330 #define k_Last_Service_Id_Key CFSTR("ServiceID")
1331 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
1334 /* Private Prototypes */
1335 static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
1336 static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
1337 static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
);
1338 static Boolean
SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
);
1339 static void addPasswordFromKeychain (SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
);
1340 static CFStringRef
copyPasswordFromKeychain (CFStringRef uniqueID
);
1342 static int notify_userprefs_token
= -1;
1344 static CFDictionaryRef onDemand_configuration
= NULL
;
1345 static pthread_mutex_t onDemand_notify_lock
= PTHREAD_MUTEX_INITIALIZER
;
1346 static int onDemand_notify_token
= -1;
1349 * return TRUE if domain1 ends with domain2, and will check for trailing "."
1352 domainEndsWithDomain(CFStringRef domain1
, CFStringRef domain2
)
1355 Boolean ret
= FALSE
;
1356 CFStringRef s1
= NULL
;
1357 Boolean s1_created
= FALSE
;
1358 CFStringRef s2
= NULL
;
1359 Boolean s2_created
= FALSE
;
1361 if (CFStringHasSuffix(domain1
, CFSTR("."))) {
1363 range
.length
= CFStringGetLength(domain1
) - 1;
1364 s1
= CFStringCreateWithSubstring(NULL
, domain1
, range
);
1373 if (CFStringHasSuffix(domain2
, CFSTR("."))) {
1375 range
.length
= CFStringGetLength(domain2
) - 1;
1376 s2
= CFStringCreateWithSubstring(NULL
, domain2
, range
);
1385 ret
= CFStringHasSuffix(s1
, s2
);
1389 if (s1_created
) CFRelease(s1
);
1390 if (s2_created
) CFRelease(s2
);
1397 __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef
*storeP
,
1398 CFStringRef hostName
,
1399 Boolean onDemandRetry
,
1400 CFStringRef
*connectionServiceID
,
1401 SCNetworkConnectionStatus
*connectionStatus
,
1402 CFStringRef
*vpnRemoteAddress
) /* CFDictionaryRef *info */
1405 CFDictionaryRef configuration
;
1408 SCDynamicStoreRef store
= *storeP
;
1409 CFArrayRef triggers
;
1410 uint64_t triggersCount
= 0;
1413 pthread_mutex_lock(&onDemand_notify_lock
);
1414 if (onDemand_notify_token
== -1) {
1415 status
= notify_register_check(kSCNETWORKCONNECTION_ONDEMAND_NOTIFY_KEY
, &onDemand_notify_token
);
1416 if (status
!= NOTIFY_STATUS_OK
) {
1417 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_register_check() failed, status=%lu"), status
);
1418 onDemand_notify_token
= -1;
1421 if (onDemand_notify_token
!= -1) {
1422 status
= notify_check(onDemand_notify_token
, &changed
);
1423 if (status
!= NOTIFY_STATUS_OK
) {
1424 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_check() failed, status=%lu"), status
);
1425 (void)notify_cancel(onDemand_notify_token
);
1426 onDemand_notify_token
= -1;
1430 if (changed
&& (onDemand_notify_token
!= -1)) {
1431 status
= notify_get_state(onDemand_notify_token
, &triggersCount
);
1432 if (status
!= NOTIFY_STATUS_OK
) {
1433 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_get_state() failed, status=%lu"), status
);
1434 (void)notify_cancel(onDemand_notify_token
);
1435 onDemand_notify_token
= -1;
1442 if (_sc_debug
|| (debug
> 0)) {
1443 SCLog(TRUE
, LOG_INFO
,
1444 CFSTR("OnDemand information %s"),
1445 (onDemand_configuration
== NULL
) ? "fetched" : "updated");
1448 if (onDemand_configuration
!= NULL
) {
1449 CFRelease(onDemand_configuration
);
1450 onDemand_configuration
= NULL
;
1453 if (triggersCount
> 0) {
1454 if (store
== NULL
) {
1455 store
= SCDynamicStoreCreate(NULL
, CFSTR("__SCNetworkConnectionCopyOnDemandInfoWithName"), NULL
, NULL
);
1456 if (store
== NULL
) {
1457 SCLog(TRUE
, LOG_ERR
, CFSTR("__SCNetworkConnectionCopyOnDemandInfoWithName SCDynamicStoreCreate() failed"));
1459 // force retry on next check
1460 if (onDemand_notify_token
!= -1) {
1461 (void)notify_cancel(onDemand_notify_token
);
1462 onDemand_notify_token
= -1;
1464 pthread_mutex_unlock(&onDemand_notify_lock
);
1470 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetOnDemand
);
1471 onDemand_configuration
= SCDynamicStoreCopyValue(store
, key
);
1473 if ((onDemand_configuration
!= NULL
) && !isA_CFDictionary(onDemand_configuration
)) {
1474 CFRelease(onDemand_configuration
);
1475 onDemand_configuration
= NULL
;
1480 configuration
= (onDemand_configuration
!= NULL
) ? CFRetain(onDemand_configuration
) : NULL
;
1481 pthread_mutex_unlock(&onDemand_notify_lock
);
1483 if (configuration
== NULL
) {
1484 // if no "OnDemand" configurations
1488 triggers
= CFDictionaryGetValue(configuration
, kSCNetworkConnectionOnDemandTriggers
);
1489 triggersCount
= isA_CFArray(triggers
) ? CFArrayGetCount(triggers
) : 0;
1490 for (triggersIndex
= 0; triggersIndex
< triggersCount
; triggersIndex
++) {
1495 CFDictionaryRef trigger
;
1497 trigger
= CFArrayGetValueAtIndex(triggers
, triggersIndex
);
1498 if (!isA_CFDictionary(trigger
)) {
1499 // if not a valid "OnDemand" configuration
1504 * If we haven't tried a resulution yet, we only want to check for a name
1505 * match for domains that require to always connect.
1507 key
= onDemandRetry
? kSCNetworkConnectionOnDemandMatchDomainsOnRetry
1508 : kSCNetworkConnectionOnDemandMatchDomainsAlways
;
1509 domains
= CFDictionaryGetValue(trigger
, key
);
1510 domainsCount
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
1511 for (domainsIndex
= 0; domainsIndex
< domainsCount
; domainsIndex
++) {
1514 domain
= CFArrayGetValueAtIndex(domains
, domainsIndex
);
1515 if (!isA_CFString(domain
)) {
1516 // if not a valid match domain
1520 if (domainEndsWithDomain(hostName
, domain
)) {
1521 CFArrayRef exceptions
;
1522 int exceptionsCount
;
1523 int exceptionsIndex
;
1525 SCNetworkConnectionStatus onDemandStatus
= kSCNetworkConnectionDisconnected
;
1527 // we have a matching domain, check against exception list
1528 exceptions
= CFDictionaryGetValue(trigger
, kSCNetworkConnectionOnDemandMatchDomainsNever
);
1529 exceptionsCount
= isA_CFArray(exceptions
) ? CFArrayGetCount(exceptions
) : 0;
1530 for (exceptionsIndex
= 0; exceptionsIndex
< exceptionsCount
; exceptionsIndex
++) {
1531 CFStringRef exception
;
1533 exception
= CFArrayGetValueAtIndex(exceptions
, exceptionsIndex
);
1534 if (!isA_CFString(exception
)) {
1535 // if not a valid match exception
1539 if (domainEndsWithDomain(hostName
, exception
)) {
1540 // found matching exception
1541 if (_sc_debug
|| (debug
> 0)) {
1542 SCLog(TRUE
, LOG_INFO
, CFSTR("OnDemand match exception"));
1548 // if we have a matching domain and there were no exceptions
1549 // then we pass back the OnDemand info
1551 if (!CFDictionaryGetValueIfPresent(trigger
,
1552 kSCNetworkConnectionOnDemandStatus
,
1553 (const void **)&num
) ||
1554 !isA_CFNumber(num
) ||
1555 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &onDemandStatus
)) {
1556 onDemandStatus
= kSCNetworkConnectionDisconnected
;
1558 if (connectionStatus
!= NULL
) {
1559 *connectionStatus
= onDemandStatus
;
1562 if (connectionServiceID
!= NULL
) {
1563 *connectionServiceID
= CFDictionaryGetValue(trigger
, kSCNetworkConnectionOnDemandServiceID
);
1564 *connectionServiceID
= isA_CFString(*connectionServiceID
);
1565 if (*connectionServiceID
!= NULL
) {
1566 CFRetain(*connectionServiceID
);
1571 if (vpnRemoteAddress
!= NULL
) {
1572 *vpnRemoteAddress
= CFDictionaryGetValue(trigger
, kSCNetworkConnectionOnDemandRemoteAddress
);
1573 *vpnRemoteAddress
= isA_CFString(*vpnRemoteAddress
);
1574 if (*vpnRemoteAddress
!= NULL
) {
1575 CFRetain(*vpnRemoteAddress
);
1579 if (_sc_debug
|| (debug
> 0)) {
1580 SCLog(TRUE
, LOG_INFO
,
1581 CFSTR("OnDemand%s match, connection status = %d"),
1582 onDemandRetry
? " (on retry)" : "",
1592 // if (_sc_debug || (debug > 0)) {
1593 // SCLog(TRUE, LOG_INFO, CFSTR("OnDemand domain name(s) not matched"));
1598 if (configuration
!= NULL
) CFRelease(configuration
);
1604 SCNetworkConnectionCopyUserPreferences(CFDictionaryRef selectionOptions
,
1605 CFStringRef
*serviceID
,
1606 CFDictionaryRef
*userOptions
)
1608 int prefsChanged
= 1;
1609 SCDynamicStoreRef session
= NULL
;
1610 Boolean success
= FALSE
;
1614 /* initialize runtime */
1615 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
1617 /* first check for new VPN OnDemand style */
1618 if (selectionOptions
!= NULL
) {
1619 CFStringRef hostName
;
1621 hostName
= CFDictionaryGetValue(selectionOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
);
1622 if (isA_CFString(hostName
)) {
1623 CFStringRef connectionServiceID
= NULL
;
1624 SCNetworkConnectionStatus connectionStatus
;
1625 Boolean onDemandRetry
;
1628 val
= CFDictionaryGetValue(selectionOptions
, kSCNetworkConnectionSelectionOptionOnDemandRetry
);
1629 onDemandRetry
= isA_CFBoolean(val
) ? CFBooleanGetValue(val
) : TRUE
;
1631 success
= __SCNetworkConnectionCopyOnDemandInfoWithName(&session
,
1634 &connectionServiceID
,
1638 SCLog(TRUE
, LOG_DEBUG
,
1639 CFSTR("SCNetworkConnectionCopyUserPreferences __SCNetworkConnectionCopyOnDemandInfoWithName returns %d w/status %d"),
1645 // if the hostname matches an OnDemand domain
1646 if (session
!= NULL
) {
1649 if (connectionStatus
== kSCNetworkConnectionConnected
) {
1650 // if we are already connected
1651 if (connectionServiceID
!= NULL
) {
1652 CFRelease(connectionServiceID
);
1657 *serviceID
= connectionServiceID
;
1658 *userOptions
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1659 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
, hostName
);
1661 } else if (!onDemandRetry
) {
1662 // if the hostname does not match an OnDemand domain and we have
1663 // not yet issued an initial DNS query (i.e. it's not a query
1664 // being retried after the VPN has been established) than we're
1666 if (session
!= NULL
) {
1674 if (notify_userprefs_token
== -1) {
1675 status
= notify_register_check(k_NetworkConnect_Notification
, ¬ify_userprefs_token
);
1676 if (status
!= NOTIFY_STATUS_OK
) {
1677 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_register_check() failed, status=%lu"), status
);
1678 (void)notify_cancel(notify_userprefs_token
);
1679 notify_userprefs_token
= -1;
1681 // clear the "something has changed" state
1682 (void) notify_check(notify_userprefs_token
, &prefsChanged
);
1686 if (notify_userprefs_token
!= -1) {
1687 status
= notify_check(notify_userprefs_token
, &prefsChanged
);
1688 if (status
!= NOTIFY_STATUS_OK
) {
1689 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_check() failed, status=%lu"), status
);
1690 (void)notify_cancel(notify_userprefs_token
);
1691 notify_userprefs_token
= -1;
1697 *userOptions
= NULL
;
1699 if (session
== NULL
) {
1700 session
= SCDynamicStoreCreate(NULL
, CFSTR("SCNetworkConnection"), NULL
, NULL
);
1702 if (session
== NULL
) {
1703 SCLog(TRUE
, LOG_ERR
, CFSTR("Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!"));
1707 if (selectionOptions
!= NULL
) {
1708 Boolean catchAllFound
= FALSE
;
1709 CFIndex catchAllService
= 0;
1710 CFIndex catchAllConfig
= 0;
1711 CFStringRef hostName
= NULL
;
1712 CFStringRef priority
= NULL
;
1713 CFArrayRef serviceNames
= NULL
;
1714 CFDictionaryRef services
= NULL
;
1715 CFIndex serviceIndex
;
1716 CFIndex servicesCount
;
1718 hostName
= CFDictionaryGetValue(selectionOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
);
1719 if (hostName
== NULL
) {
1720 hostName
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandHostName
);
1722 hostName
= isA_CFString(hostName
);
1723 if (hostName
== NULL
)
1724 goto done_selection
; // if no hostname for matching
1726 priority
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandPriority
);
1727 if (!isA_CFString(priority
))
1728 priority
= kSCValNetPPPOnDemandPriorityDefault
;
1731 if (!isA_CFArray(serviceNames
))
1732 goto done_selection
;
1735 if (!isA_CFDictionary(services
))
1736 goto done_selection
;
1738 servicesCount
= CFArrayGetCount(serviceNames
);
1739 for (serviceIndex
= 0; serviceIndex
< servicesCount
; serviceIndex
++) {
1740 CFIndex configIndex
;
1741 CFIndex configsCount
;
1742 CFArrayRef serviceConfigs
;
1743 CFStringRef serviceName
;
1746 serviceName
= CFArrayGetValueAtIndex(serviceNames
, serviceIndex
);
1747 if (!isA_CFString(serviceName
))
1750 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1751 if (!isA_CFArray(serviceConfigs
))
1754 configsCount
= CFArrayGetCount(serviceConfigs
);
1755 for (configIndex
= 0; configIndex
< configsCount
; configIndex
++) {
1756 CFNumberRef autodial
;
1757 CFDictionaryRef config
;
1758 CFDictionaryRef pppConfig
;
1760 config
= CFArrayGetValueAtIndex(serviceConfigs
, configIndex
);
1761 if (!isA_CFDictionary(config
))
1764 pppConfig
= CFDictionaryGetValue(config
, kSCEntNetPPP
);
1765 if (!isA_CFDictionary(pppConfig
))
1768 autodial
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandEnabled
);
1769 if (!isA_CFNumber(autodial
))
1772 CFNumberGetValue(autodial
, kCFNumberIntType
, &val
);
1775 CFIndex domainsCount
;
1776 CFIndex domainsIndex
;
1778 /* we found an conditional connection enabled configuration */
1781 domains
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandDomains
);
1782 if (!isA_CFArray(domains
))
1785 domainsCount
= CFArrayGetCount(domains
);
1786 for (domainsIndex
= 0; domainsIndex
< domainsCount
; domainsIndex
++) {
1789 domain
= CFArrayGetValueAtIndex(domains
, domainsIndex
);
1790 if (!isA_CFString(domain
))
1793 if (!catchAllFound
&&
1794 (CFStringCompare(domain
, CFSTR(""), 0) == kCFCompareEqualTo
1795 || CFStringCompare(domain
, CFSTR("."), 0) == kCFCompareEqualTo
)) {
1796 // found a catch all
1797 catchAllFound
= TRUE
;
1798 catchAllService
= serviceIndex
;
1799 catchAllConfig
= configIndex
;
1802 if (domainEndsWithDomain(hostName
, domain
)) {
1803 // found matching configuration
1804 *serviceID
= serviceName
;
1805 CFRetain(*serviceID
);
1806 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1807 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
, hostName
);
1808 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1809 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1811 goto done_selection
;
1818 // config not found, do we have a catchall ?
1819 if (catchAllFound
) {
1820 CFDictionaryRef config
;
1821 CFArrayRef serviceConfigs
;
1822 CFStringRef serviceName
;
1824 serviceName
= CFArrayGetValueAtIndex(serviceNames
, catchAllService
);
1825 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1826 config
= CFArrayGetValueAtIndex(serviceConfigs
, catchAllConfig
);
1828 *serviceID
= serviceName
;
1829 CFRetain(*serviceID
);
1830 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1831 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
, hostName
);
1832 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1833 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1835 goto done_selection
;
1841 CFRelease(serviceNames
);
1843 CFRelease(services
);
1847 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@"), success
? CFSTR("succeeded") : CFSTR("failed"));
1848 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Selection options: %@"), selectionOptions
);
1854 /* we don't have selection options */
1856 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
1857 success
= SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session
, serviceID
);
1859 if (success
&& (*serviceID
!= NULL
)) {
1860 // (2) Get the list of user data for this service ID
1861 CFPropertyListRef userServices
= NULL
;
1864 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
1865 if (userServices
!= NULL
) {
1866 if (isA_CFArray(userServices
)) {
1867 // (4) Get the default set of user options for this service
1868 success
= SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray((CFArrayRef
)userServices
,
1870 if(success
&& (userOptions
!= NULL
)) {
1871 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1874 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Error, userServices are not of type CFArray!"));
1877 CFRelease(userServices
); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
1882 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@, no selection options"), success
? CFSTR("succeeded") : CFSTR("failed"));
1890 //*******************************************************************************************
1891 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
1892 // ----------------------------------------------------
1893 // Try to find the service id to connect
1894 // (1) Start by looking at the last service used in Network Pref / Network menu extra
1895 // (2) If Network Pref / Network menu extra has not been used, find the PPP service
1896 // with the highest ordering
1897 //********************************************************************************************
1899 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1901 Boolean foundService
= FALSE
;
1902 CFPropertyListRef lastServiceSelectedInIC
= NULL
;
1906 // we found the service the user last had open in IC
1907 if (lastServiceSelectedInIC
!= NULL
) {
1908 // make sure its a PPP service
1909 if (SCNetworkConnectionPrivateIsPPPService(session
, lastServiceSelectedInIC
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1910 // make sure the service that we found is valid
1911 CFDictionaryRef dict
;
1914 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1915 kSCDynamicStoreDomainSetup
,
1916 lastServiceSelectedInIC
,
1917 kSCEntNetInterface
);
1918 dict
= SCDynamicStoreCopyValue(session
, key
);
1922 *serviceID
= CFRetain(lastServiceSelectedInIC
);
1923 foundService
= TRUE
;
1926 CFRelease(lastServiceSelectedInIC
);
1929 if (!foundService
) {
1930 foundService
= SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session
, serviceID
);
1933 return foundService
;
1936 //********************************************************************************
1937 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
1938 // -------------------------------------------------------
1939 // Find the highest ordered PPP service in the dynamic store
1940 //********************************************************************************
1942 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1944 CFDictionaryRef dict
= NULL
;
1945 CFStringRef key
= NULL
;
1946 CFArrayRef serviceIDs
= NULL
;
1947 Boolean success
= FALSE
;
1955 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCEntNetIPv4
);
1957 fprintf(stderr
, "Error, Setup Key == NULL!\n");
1961 dict
= SCDynamicStoreCopyValue(session
, key
);
1962 if (!isA_CFDictionary(dict
)) {
1963 fprintf(stderr
, "no global IPv4 entity\n");
1967 serviceIDs
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
); // array of service id's
1968 if (!isA_CFArray(serviceIDs
)) {
1969 fprintf(stderr
, "service order not specified\n");
1973 count
= CFArrayGetCount(serviceIDs
);
1974 for (i
= 0; i
< count
; i
++) {
1975 CFStringRef service
= CFArrayGetValueAtIndex(serviceIDs
, i
);
1977 if (SCNetworkConnectionPrivateIsPPPService(session
, service
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1978 *serviceID
= CFRetain(service
);
1985 if (key
!= NULL
) CFRelease(key
);
1986 if (dict
!= NULL
) CFRelease(dict
);
1991 //********************************************************************************
1992 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
1993 // ---------------------------------------------------------
1994 // Copy over user preferences for a particular service if they exist
1995 //********************************************************************************
1997 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
)
1999 CFIndex count
= CFArrayGetCount(userOptionsArray
);
2002 for (i
= 0; i
< count
; i
++) {
2003 // (1) Find the dictionary
2004 CFPropertyListRef propertyList
= CFArrayGetValueAtIndex(userOptionsArray
, i
);
2006 if (isA_CFDictionary(propertyList
) != NULL
) {
2007 // See if there's a value for dial on demand
2008 CFPropertyListRef value
;
2010 value
= CFDictionaryGetValue((CFDictionaryRef
)propertyList
, k_Dial_Default_Key
);
2011 if (isA_CFBoolean(value
) != NULL
) {
2012 if (CFBooleanGetValue(value
)) {
2013 // we found the default user options
2014 *userOptions
= CFDictionaryCreateCopy(NULL
,
2015 (CFDictionaryRef
)propertyList
);
2025 //********************************************************************************
2026 // SCNetworkConnectionPrivateIsServiceType
2027 // --------------------------------------
2028 // Check and see if the service is a PPP service of the given types
2029 //********************************************************************************
2031 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
)
2033 CFStringRef entityKey
;
2034 Boolean isPPPService
= FALSE
;
2035 Boolean isMatchingSubType
= FALSE
;
2036 CFDictionaryRef serviceDict
;
2038 entityKey
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
2039 kSCDynamicStoreDomainSetup
,
2041 kSCEntNetInterface
);
2042 if (entityKey
== NULL
) {
2046 serviceDict
= SCDynamicStoreCopyValue(session
, entityKey
);
2047 if (serviceDict
!= NULL
) {
2048 if (isA_CFDictionary(serviceDict
)) {
2050 CFStringRef subtype
;
2052 type
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceType
);
2053 if (isA_CFString(type
)) {
2054 isPPPService
= CFEqual(type
, kSCValNetInterfaceTypePPP
);
2057 subtype
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceSubType
);
2058 if (isA_CFString(subtype
)) {
2059 isMatchingSubType
= CFEqual(subtype
, subType1
);
2060 if (!isMatchingSubType
&& subType2
)
2061 isMatchingSubType
= CFEqual(subtype
, subType2
);
2064 CFRelease(serviceDict
);
2066 CFRelease(entityKey
);
2068 return (isPPPService
&& isMatchingSubType
);
2071 //********************************************************************************
2072 // addPasswordFromKeychain
2073 // --------------------------------------
2074 // Get the password and shared secret out of the keychain and add
2075 // them to the PPP and IPSec dictionaries
2076 //********************************************************************************
2078 addPasswordFromKeychain(SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
)
2080 CFPropertyListRef uniqueID
;
2081 CFStringRef password
;
2082 CFStringRef sharedsecret
= NULL
;
2084 /* user options must exist */
2085 if (*userOptions
== NULL
)
2088 /* first, get the unique identifier used to store passwords in the keychain */
2089 uniqueID
= CFDictionaryGetValue(*userOptions
, k_Unique_Id_Key
);
2090 if (!isA_CFString(uniqueID
))
2093 /* first, get the PPP password */
2094 password
= copyPasswordFromKeychain(uniqueID
);
2096 /* then, if necessary, get the IPSec Shared Secret */
2097 if (SCNetworkConnectionPrivateIsPPPService(session
, serviceID
, kSCValNetInterfaceSubTypeL2TP
, 0)) {
2098 CFMutableStringRef uniqueIDSS
;
2100 uniqueIDSS
= CFStringCreateMutableCopy(NULL
, 0, uniqueID
);
2101 CFStringAppend(uniqueIDSS
, CFSTR(".SS"));
2102 sharedsecret
= copyPasswordFromKeychain(uniqueIDSS
);
2103 CFRelease(uniqueIDSS
);
2106 /* did we find our information in the key chain ? */
2107 if ((password
!= NULL
) || (sharedsecret
!= NULL
)) {
2108 CFMutableDictionaryRef newOptions
;
2110 newOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, *userOptions
);
2113 if (password
!= NULL
) {
2114 CFDictionaryRef entity
;
2115 CFMutableDictionaryRef newEntity
;
2117 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetPPP
);
2118 if (isA_CFDictionary(entity
))
2119 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
2121 newEntity
= CFDictionaryCreateMutable(NULL
,
2123 &kCFTypeDictionaryKeyCallBacks
,
2124 &kCFTypeDictionaryValueCallBacks
);
2127 /* set the PPP password */
2128 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPassword
, uniqueID
);
2129 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPasswordEncryption
, kSCValNetPPPAuthPasswordEncryptionKeychain
);
2130 CFRelease(password
);
2132 /* update the PPP entity */
2133 CFDictionarySetValue(newOptions
, kSCEntNetPPP
, newEntity
);
2134 CFRelease(newEntity
);
2137 /* IPSec Shared Secret */
2138 if (sharedsecret
!= NULL
) {
2139 CFDictionaryRef entity
;
2140 CFMutableDictionaryRef newEntity
;
2142 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetIPSec
);
2143 if (isA_CFDictionary(entity
))
2144 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
2146 newEntity
= CFDictionaryCreateMutable(NULL
,
2148 &kCFTypeDictionaryKeyCallBacks
,
2149 &kCFTypeDictionaryValueCallBacks
);
2151 /* set the IPSec Shared Secret */
2152 CFDictionarySetValue(newEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
2153 CFRelease(sharedsecret
);
2155 /* update the IPSec entity */
2156 CFDictionarySetValue(newOptions
, kSCEntNetIPSec
, newEntity
);
2157 CFRelease(newEntity
);
2160 /* update the userOptions dictionary */
2161 CFRelease(*userOptions
);
2162 *userOptions
= CFDictionaryCreateCopy(NULL
, newOptions
);
2163 CFRelease(newOptions
);
2168 #if !TARGET_OS_IPHONE
2169 //********************************************************************************
2170 // copyKeychainEnumerator
2171 // --------------------------------------
2172 // Gather Keychain Enumerator
2173 //********************************************************************************
2175 copyKeychainEnumerator(CFStringRef uniqueIdentifier
)
2178 CFMutableArrayRef itemArray
= NULL
;
2180 SecKeychainSearchRef search
= NULL
;
2182 buf
= _SC_cfstring_to_cstring(uniqueIdentifier
, NULL
, 0, kCFStringEncodingUTF8
);
2184 // search for unique identifier in "svce" attribute
2185 SecKeychainAttribute attributes
[] = {{ kSecServiceItemAttr
,
2186 CFStringGetLength(uniqueIdentifier
),
2190 SecKeychainAttributeList attrList
= { sizeof(attributes
) / sizeof(*attributes
),
2193 result
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attrList
, &search
);
2194 if (result
== noErr
) {
2195 itemArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2197 while (result
== noErr
) {
2198 SecKeychainItemRef itemFound
= NULL
;
2200 result
= SecKeychainSearchCopyNext(search
, &itemFound
);
2201 if (result
!= noErr
) {
2206 CFArrayAppendValue(itemArray
, itemFound
);
2207 CFRelease(itemFound
);
2213 if (search
) CFRelease(search
);
2214 if (buf
) CFAllocatorDeallocate(NULL
, buf
);
2218 #endif // !TARGET_OS_IPHONE
2220 //********************************************************************************
2221 // copyPasswordFromKeychain
2222 // --------------------------------------
2223 // Given a uniqueID, retrieve the password from the keychain
2224 //********************************************************************************
2226 copyPasswordFromKeychain(CFStringRef uniqueID
)
2228 #if !TARGET_OS_IPHONE
2229 CFArrayRef enumerator
;
2231 CFStringRef password
= NULL
;
2233 enumerator
= copyKeychainEnumerator(uniqueID
);
2234 if (enumerator
== NULL
) {
2235 return NULL
; // if no keychain enumerator
2238 n
= CFArrayGetCount(enumerator
);
2242 SecKeychainItemRef itemRef
;
2245 itemRef
= (SecKeychainItemRef
)CFArrayGetValueAtIndex(enumerator
, 0);
2246 result
= SecKeychainItemCopyContent(itemRef
, // itemRef
2250 (void *)&data
); // outData
2251 if ((result
== noErr
) && (data
!= NULL
) && (dataLen
> 0)) {
2252 password
= CFStringCreateWithBytes(NULL
, data
, dataLen
, kCFStringEncodingUTF8
, TRUE
);
2253 (void) SecKeychainItemFreeContent(NULL
, data
);
2258 CFRelease(enumerator
);
2261 #else // !TARGET_OS_IPHONE
2263 #endif // !TARGET_OS_IPHONE