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
) {
1111 dispatch_queue_attr_t attr
;
1115 connectionPrivate
->dispatchQueue
= queue
;
1116 dispatch_retain(connectionPrivate
->dispatchQueue
);
1118 attr
= dispatch_queue_attr_create();
1119 res
= dispatch_queue_attr_set_finalizer(attr
,
1120 ^(dispatch_queue_t dq
) {
1121 SCNetworkConnectionRef connection
;
1123 connection
= (SCNetworkConnectionRef
)dispatch_get_context(dq
);
1124 CFRelease(connection
);
1127 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkConnection dispatch_queue_attr_set_finalizer() failed"));
1128 dispatch_release(attr
);
1131 connectionPrivate
->callbackQueue
= dispatch_queue_create("com.apple.SCNetworkConnection.notifications", attr
);
1132 dispatch_release(attr
);
1133 if (connectionPrivate
->callbackQueue
== NULL
){
1134 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkConnection dispatch_queue_create() failed"));
1137 CFRetain(connection
); // Note: will be released when the dispatch queue is released
1138 dispatch_set_context(connectionPrivate
->callbackQueue
, connectionPrivate
);
1140 mp
= CFMachPortGetPort(connectionPrivate
->notify_port
);
1141 connectionPrivate
->callbackSource
= dispatch_source_mig_create(mp
, sizeof(mach_msg_header_t
), NULL
, connectionPrivate
->callbackQueue
, SCNetworkConnectionNotifyMIGCallback
);
1142 if (connectionPrivate
->callbackSource
== NULL
) {
1143 SCLog(TRUE
, LOG_ERR
, CFSTR("SCNetworkConnection dispatch_source_mig_create() failed"));
1147 #endif // !TARGET_OS_IPHONE
1149 if (!_SC_isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
1151 * if we do not already have notifications scheduled with
1152 * this runLoop / runLoopMode
1154 CFRunLoopAddSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
1157 _SC_schedule(connection
, runLoop
, runLoopMode
, connectionPrivate
->rlList
);
1162 #if !TARGET_OS_IPHONE
1165 if (connectionPrivate
->callbackSource
!= NULL
) {
1166 dispatch_cancel(connectionPrivate
->callbackSource
);
1167 dispatch_release(connectionPrivate
->callbackSource
);
1168 connectionPrivate
->callbackSource
= NULL
;
1170 if (connectionPrivate
->callbackQueue
!= NULL
) {
1171 dispatch_release(connectionPrivate
->callbackQueue
);
1172 connectionPrivate
->callbackQueue
= NULL
;
1174 if (connectionPrivate
->dispatchQueue
!= NULL
) {
1175 dispatch_release(connectionPrivate
->dispatchQueue
);
1176 connectionPrivate
->dispatchQueue
= NULL
;
1178 _SCErrorSet(kSCStatusFailed
);
1180 #endif // !TARGET_OS_IPHONE
1185 __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
1186 CFRunLoopRef runLoop
,
1187 CFStringRef runLoopMode
,
1188 #if !TARGET_OS_IPHONE
1189 dispatch_queue_t queue
1190 #else // !TARGET_OS_IPHONE
1192 #endif // !TARGET_OS_IPHONE
1195 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
1196 int error
= kSCStatusFailed
;
1198 mach_port_t session_port
;
1199 kern_return_t status
;
1201 if ((runLoop
!= NULL
) && !connectionPrivate
->scheduled
) { // if we should be scheduled (but are not)
1202 _SCErrorSet(kSCStatusInvalidArgument
);
1206 #if !TARGET_OS_IPHONE
1207 if (((runLoop
== NULL
) && (connectionPrivate
->dispatchQueue
== NULL
)) || // if we should be scheduled on a dispatch queue (but are not)
1208 ((runLoop
!= NULL
) && (connectionPrivate
->dispatchQueue
!= NULL
))) { // if we should be scheduled on a CFRunLoop (but are scheduled on a dispatch queue)
1209 _SCErrorSet(kSCStatusInvalidArgument
);
1212 #endif // !TARGET_OS_IPHONE
1214 session_port
= __SCNetworkConnectionSessionPort(connectionPrivate
);
1215 if (session_port
== MACH_PORT_NULL
) {
1216 _SCErrorSet(kSCStatusInvalidArgument
);
1220 #if !TARGET_OS_IPHONE
1221 if (runLoop
== NULL
) {
1222 dispatch_cancel(connectionPrivate
->callbackSource
);
1223 dispatch_release(connectionPrivate
->callbackSource
);
1224 connectionPrivate
->callbackSource
= NULL
;
1225 dispatch_release(connectionPrivate
->callbackQueue
);
1226 connectionPrivate
->callbackQueue
= NULL
;
1227 dispatch_release(connectionPrivate
->dispatchQueue
);
1228 connectionPrivate
->dispatchQueue
= NULL
;
1230 #endif // !TARGET_OS_IPHONE
1232 if (!_SC_unschedule(connection
, runLoop
, runLoopMode
, connectionPrivate
->rlList
, FALSE
)) {
1233 // if not currently scheduled on this runLoop / runLoopMode
1234 _SCErrorSet(kSCStatusFailed
);
1238 n
= CFArrayGetCount(connectionPrivate
->rlList
);
1239 if (n
== 0 || !_SC_isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
1241 * if we are no longer scheduled to receive notifications for
1242 * this runLoop / runLoopMode
1244 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
1247 // if *all* notifications have been unscheduled
1248 CFRelease(connectionPrivate
->rlList
);
1249 connectionPrivate
->rlList
= NULL
;
1250 CFRunLoopSourceInvalidate(connectionPrivate
->rls
);
1251 CFRelease(connectionPrivate
->rls
);
1252 connectionPrivate
->rls
= NULL
;
1258 // if *all* notifications have been unscheduled
1259 connectionPrivate
->scheduled
= FALSE
;
1261 status
= pppcontroller_notification(session_port
, 0, &error
);
1262 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
1273 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
1274 CFRunLoopRef runLoop
,
1275 CFStringRef runLoopMode
)
1277 if (!isA_SCNetworkConnection(connection
) || (runLoop
== NULL
) || (runLoopMode
== NULL
)) {
1278 _SCErrorSet(kSCStatusInvalidArgument
);
1282 return __SCNetworkConnectionScheduleWithRunLoop(connection
, runLoop
, runLoopMode
, NULL
);
1287 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
1288 CFRunLoopRef runLoop
,
1289 CFStringRef runLoopMode
)
1291 if (!isA_SCNetworkConnection(connection
) || (runLoop
== NULL
) || (runLoopMode
== NULL
)) {
1292 _SCErrorSet(kSCStatusInvalidArgument
);
1296 return __SCNetworkConnectionUnscheduleFromRunLoop(connection
, runLoop
, runLoopMode
, NULL
);
1300 #if !TARGET_OS_IPHONE
1302 SCNetworkConnectionSetDispatchQueue(SCNetworkConnectionRef connection
,
1303 dispatch_queue_t queue
)
1307 if (!isA_SCNetworkConnection(connection
)) {
1308 _SCErrorSet(kSCStatusInvalidArgument
);
1312 if (queue
!= NULL
) {
1313 ok
= __SCNetworkConnectionScheduleWithRunLoop(connection
, NULL
, NULL
, queue
);
1315 ok
= __SCNetworkConnectionUnscheduleFromRunLoop(connection
, NULL
, NULL
, NULL
);
1320 #endif // !TARGET_OS_IPHONE
1324 #pragma mark User level "dial" API
1327 #define k_NetworkConnect_Notification "com.apple.networkConnect"
1328 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
1329 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
1331 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
1332 #define k_Last_Service_Id_Key CFSTR("ServiceID")
1333 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
1336 /* Private Prototypes */
1337 static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
1338 static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
1339 static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
);
1340 static Boolean
SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
);
1341 static void addPasswordFromKeychain (SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
);
1342 static CFStringRef
copyPasswordFromKeychain (CFStringRef uniqueID
);
1344 static int notify_userprefs_token
= -1;
1346 static CFDictionaryRef onDemand_configuration
= NULL
;
1347 static pthread_mutex_t onDemand_notify_lock
= PTHREAD_MUTEX_INITIALIZER
;
1348 static int onDemand_notify_token
= -1;
1351 * return TRUE if domain1 ends with domain2, and will check for trailing "."
1354 domainEndsWithDomain(CFStringRef domain1
, CFStringRef domain2
)
1357 Boolean ret
= FALSE
;
1358 CFStringRef s1
= NULL
;
1359 Boolean s1_created
= FALSE
;
1360 CFStringRef s2
= NULL
;
1361 Boolean s2_created
= FALSE
;
1363 if (CFStringHasSuffix(domain1
, CFSTR("."))) {
1365 range
.length
= CFStringGetLength(domain1
) - 1;
1366 s1
= CFStringCreateWithSubstring(NULL
, domain1
, range
);
1375 if (CFStringHasSuffix(domain2
, CFSTR("."))) {
1377 range
.length
= CFStringGetLength(domain2
) - 1;
1378 s2
= CFStringCreateWithSubstring(NULL
, domain2
, range
);
1387 ret
= CFStringHasSuffix(s1
, s2
);
1391 if (s1_created
) CFRelease(s1
);
1392 if (s2_created
) CFRelease(s2
);
1399 __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef
*storeP
,
1400 CFStringRef hostName
,
1401 Boolean onDemandRetry
,
1402 CFStringRef
*connectionServiceID
,
1403 SCNetworkConnectionStatus
*connectionStatus
,
1404 CFStringRef
*vpnRemoteAddress
) /* CFDictionaryRef *info */
1407 CFDictionaryRef configuration
;
1410 SCDynamicStoreRef store
= *storeP
;
1411 CFArrayRef triggers
;
1412 uint64_t triggersCount
= 0;
1415 pthread_mutex_lock(&onDemand_notify_lock
);
1416 if (onDemand_notify_token
== -1) {
1417 status
= notify_register_check(kSCNETWORKCONNECTION_ONDEMAND_NOTIFY_KEY
, &onDemand_notify_token
);
1418 if (status
!= NOTIFY_STATUS_OK
) {
1419 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_register_check() failed, status=%lu"), status
);
1420 onDemand_notify_token
= -1;
1423 if (onDemand_notify_token
!= -1) {
1424 status
= notify_check(onDemand_notify_token
, &changed
);
1425 if (status
!= NOTIFY_STATUS_OK
) {
1426 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_check() failed, status=%lu"), status
);
1427 (void)notify_cancel(onDemand_notify_token
);
1428 onDemand_notify_token
= -1;
1432 if (changed
&& (onDemand_notify_token
!= -1)) {
1433 status
= notify_get_state(onDemand_notify_token
, &triggersCount
);
1434 if (status
!= NOTIFY_STATUS_OK
) {
1435 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_get_state() failed, status=%lu"), status
);
1436 (void)notify_cancel(onDemand_notify_token
);
1437 onDemand_notify_token
= -1;
1444 if (_sc_debug
|| (debug
> 0)) {
1445 SCLog(TRUE
, LOG_INFO
,
1446 CFSTR("OnDemand information %s"),
1447 (onDemand_configuration
== NULL
) ? "fetched" : "updated");
1450 if (onDemand_configuration
!= NULL
) {
1451 CFRelease(onDemand_configuration
);
1452 onDemand_configuration
= NULL
;
1455 if (triggersCount
> 0) {
1456 if (store
== NULL
) {
1457 store
= SCDynamicStoreCreate(NULL
, CFSTR("__SCNetworkConnectionCopyOnDemandInfoWithName"), NULL
, NULL
);
1458 if (store
== NULL
) {
1459 SCLog(TRUE
, LOG_ERR
, CFSTR("__SCNetworkConnectionCopyOnDemandInfoWithName SCDynamicStoreCreate() failed"));
1461 // force retry on next check
1462 if (onDemand_notify_token
!= -1) {
1463 (void)notify_cancel(onDemand_notify_token
);
1464 onDemand_notify_token
= -1;
1466 pthread_mutex_unlock(&onDemand_notify_lock
);
1472 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainState
, kSCEntNetOnDemand
);
1473 onDemand_configuration
= SCDynamicStoreCopyValue(store
, key
);
1475 if ((onDemand_configuration
!= NULL
) && !isA_CFDictionary(onDemand_configuration
)) {
1476 CFRelease(onDemand_configuration
);
1477 onDemand_configuration
= NULL
;
1482 configuration
= (onDemand_configuration
!= NULL
) ? CFRetain(onDemand_configuration
) : NULL
;
1483 pthread_mutex_unlock(&onDemand_notify_lock
);
1485 if (configuration
== NULL
) {
1486 // if no "OnDemand" configurations
1490 triggers
= CFDictionaryGetValue(configuration
, kSCNetworkConnectionOnDemandTriggers
);
1491 triggersCount
= isA_CFArray(triggers
) ? CFArrayGetCount(triggers
) : 0;
1492 for (triggersIndex
= 0; triggersIndex
< triggersCount
; triggersIndex
++) {
1497 CFDictionaryRef trigger
;
1499 trigger
= CFArrayGetValueAtIndex(triggers
, triggersIndex
);
1500 if (!isA_CFDictionary(trigger
)) {
1501 // if not a valid "OnDemand" configuration
1506 * If we haven't tried a resulution yet, we only want to check for a name
1507 * match for domains that require to always connect.
1509 key
= onDemandRetry
? kSCNetworkConnectionOnDemandMatchDomainsOnRetry
1510 : kSCNetworkConnectionOnDemandMatchDomainsAlways
;
1511 domains
= CFDictionaryGetValue(trigger
, key
);
1512 domainsCount
= isA_CFArray(domains
) ? CFArrayGetCount(domains
) : 0;
1513 for (domainsIndex
= 0; domainsIndex
< domainsCount
; domainsIndex
++) {
1516 domain
= CFArrayGetValueAtIndex(domains
, domainsIndex
);
1517 if (!isA_CFString(domain
)) {
1518 // if not a valid match domain
1522 if (domainEndsWithDomain(hostName
, domain
)) {
1523 CFArrayRef exceptions
;
1524 int exceptionsCount
;
1525 int exceptionsIndex
;
1527 SCNetworkConnectionStatus onDemandStatus
= kSCNetworkConnectionDisconnected
;
1529 // we have a matching domain, check against exception list
1530 exceptions
= CFDictionaryGetValue(trigger
, kSCNetworkConnectionOnDemandMatchDomainsNever
);
1531 exceptionsCount
= isA_CFArray(exceptions
) ? CFArrayGetCount(exceptions
) : 0;
1532 for (exceptionsIndex
= 0; exceptionsIndex
< exceptionsCount
; exceptionsIndex
++) {
1533 CFStringRef exception
;
1535 exception
= CFArrayGetValueAtIndex(exceptions
, exceptionsIndex
);
1536 if (!isA_CFString(exception
)) {
1537 // if not a valid match exception
1541 if (domainEndsWithDomain(hostName
, exception
)) {
1542 // found matching exception
1543 if (_sc_debug
|| (debug
> 0)) {
1544 SCLog(TRUE
, LOG_INFO
, CFSTR("OnDemand match exception"));
1550 // if we have a matching domain and there were no exceptions
1551 // then we pass back the OnDemand info
1553 if (!CFDictionaryGetValueIfPresent(trigger
,
1554 kSCNetworkConnectionOnDemandStatus
,
1555 (const void **)&num
) ||
1556 !isA_CFNumber(num
) ||
1557 !CFNumberGetValue(num
, kCFNumberSInt32Type
, &onDemandStatus
)) {
1558 onDemandStatus
= kSCNetworkConnectionDisconnected
;
1560 if (connectionStatus
!= NULL
) {
1561 *connectionStatus
= onDemandStatus
;
1564 if (connectionServiceID
!= NULL
) {
1565 *connectionServiceID
= CFDictionaryGetValue(trigger
, kSCNetworkConnectionOnDemandServiceID
);
1566 *connectionServiceID
= isA_CFString(*connectionServiceID
);
1567 if (*connectionServiceID
!= NULL
) {
1568 CFRetain(*connectionServiceID
);
1573 if (vpnRemoteAddress
!= NULL
) {
1574 *vpnRemoteAddress
= CFDictionaryGetValue(trigger
, kSCNetworkConnectionOnDemandRemoteAddress
);
1575 *vpnRemoteAddress
= isA_CFString(*vpnRemoteAddress
);
1576 if (*vpnRemoteAddress
!= NULL
) {
1577 CFRetain(*vpnRemoteAddress
);
1581 if (_sc_debug
|| (debug
> 0)) {
1582 SCLog(TRUE
, LOG_INFO
,
1583 CFSTR("OnDemand%s match, connection status = %d"),
1584 onDemandRetry
? " (on retry)" : "",
1594 // if (_sc_debug || (debug > 0)) {
1595 // SCLog(TRUE, LOG_INFO, CFSTR("OnDemand domain name(s) not matched"));
1600 if (configuration
!= NULL
) CFRelease(configuration
);
1606 SCNetworkConnectionCopyUserPreferences(CFDictionaryRef selectionOptions
,
1607 CFStringRef
*serviceID
,
1608 CFDictionaryRef
*userOptions
)
1610 int prefsChanged
= 1;
1611 SCDynamicStoreRef session
= NULL
;
1612 Boolean success
= FALSE
;
1616 /* initialize runtime */
1617 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
1619 /* first check for new VPN OnDemand style */
1620 if (selectionOptions
!= NULL
) {
1621 CFStringRef hostName
;
1623 hostName
= CFDictionaryGetValue(selectionOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
);
1624 if (isA_CFString(hostName
)) {
1625 CFStringRef connectionServiceID
= NULL
;
1626 SCNetworkConnectionStatus connectionStatus
;
1627 Boolean onDemandRetry
;
1630 val
= CFDictionaryGetValue(selectionOptions
, kSCNetworkConnectionSelectionOptionOnDemandRetry
);
1631 onDemandRetry
= isA_CFBoolean(val
) ? CFBooleanGetValue(val
) : TRUE
;
1633 success
= __SCNetworkConnectionCopyOnDemandInfoWithName(&session
,
1636 &connectionServiceID
,
1640 SCLog(TRUE
, LOG_DEBUG
,
1641 CFSTR("SCNetworkConnectionCopyUserPreferences __SCNetworkConnectionCopyOnDemandInfoWithName returns %d w/status %d"),
1647 // if the hostname matches an OnDemand domain
1648 if (session
!= NULL
) {
1651 if (connectionStatus
== kSCNetworkConnectionConnected
) {
1652 // if we are already connected
1653 if (connectionServiceID
!= NULL
) {
1654 CFRelease(connectionServiceID
);
1659 *serviceID
= connectionServiceID
;
1660 *userOptions
= CFDictionaryCreateMutable(NULL
, 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
1661 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
, hostName
);
1663 } else if (!onDemandRetry
) {
1664 // if the hostname does not match an OnDemand domain and we have
1665 // not yet issued an initial DNS query (i.e. it's not a query
1666 // being retried after the VPN has been established) than we're
1668 if (session
!= NULL
) {
1676 if (notify_userprefs_token
== -1) {
1677 status
= notify_register_check(k_NetworkConnect_Notification
, ¬ify_userprefs_token
);
1678 if (status
!= NOTIFY_STATUS_OK
) {
1679 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_register_check() failed, status=%lu"), status
);
1680 (void)notify_cancel(notify_userprefs_token
);
1681 notify_userprefs_token
= -1;
1683 // clear the "something has changed" state
1684 (void) notify_check(notify_userprefs_token
, &prefsChanged
);
1688 if (notify_userprefs_token
!= -1) {
1689 status
= notify_check(notify_userprefs_token
, &prefsChanged
);
1690 if (status
!= NOTIFY_STATUS_OK
) {
1691 SCLog(TRUE
, LOG_ERR
, CFSTR("notify_check() failed, status=%lu"), status
);
1692 (void)notify_cancel(notify_userprefs_token
);
1693 notify_userprefs_token
= -1;
1699 *userOptions
= NULL
;
1701 if (session
== NULL
) {
1702 session
= SCDynamicStoreCreate(NULL
, CFSTR("SCNetworkConnection"), NULL
, NULL
);
1704 if (session
== NULL
) {
1705 SCLog(TRUE
, LOG_ERR
, CFSTR("Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!"));
1709 if (selectionOptions
!= NULL
) {
1710 Boolean catchAllFound
= FALSE
;
1711 CFIndex catchAllService
= 0;
1712 CFIndex catchAllConfig
= 0;
1713 CFStringRef hostName
= NULL
;
1714 CFStringRef priority
= NULL
;
1715 CFArrayRef serviceNames
= NULL
;
1716 CFDictionaryRef services
= NULL
;
1717 CFIndex serviceIndex
;
1718 CFIndex servicesCount
;
1720 hostName
= CFDictionaryGetValue(selectionOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
);
1721 if (hostName
== NULL
) {
1722 hostName
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandHostName
);
1724 hostName
= isA_CFString(hostName
);
1725 if (hostName
== NULL
)
1726 goto done_selection
; // if no hostname for matching
1728 priority
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandPriority
);
1729 if (!isA_CFString(priority
))
1730 priority
= kSCValNetPPPOnDemandPriorityDefault
;
1733 if (!isA_CFArray(serviceNames
))
1734 goto done_selection
;
1737 if (!isA_CFDictionary(services
))
1738 goto done_selection
;
1740 servicesCount
= CFArrayGetCount(serviceNames
);
1741 for (serviceIndex
= 0; serviceIndex
< servicesCount
; serviceIndex
++) {
1742 CFIndex configIndex
;
1743 CFIndex configsCount
;
1744 CFArrayRef serviceConfigs
;
1745 CFStringRef serviceName
;
1748 serviceName
= CFArrayGetValueAtIndex(serviceNames
, serviceIndex
);
1749 if (!isA_CFString(serviceName
))
1752 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1753 if (!isA_CFArray(serviceConfigs
))
1756 configsCount
= CFArrayGetCount(serviceConfigs
);
1757 for (configIndex
= 0; configIndex
< configsCount
; configIndex
++) {
1758 CFNumberRef autodial
;
1759 CFDictionaryRef config
;
1760 CFDictionaryRef pppConfig
;
1762 config
= CFArrayGetValueAtIndex(serviceConfigs
, configIndex
);
1763 if (!isA_CFDictionary(config
))
1766 pppConfig
= CFDictionaryGetValue(config
, kSCEntNetPPP
);
1767 if (!isA_CFDictionary(pppConfig
))
1770 autodial
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandEnabled
);
1771 if (!isA_CFNumber(autodial
))
1774 CFNumberGetValue(autodial
, kCFNumberIntType
, &val
);
1777 CFIndex domainsCount
;
1778 CFIndex domainsIndex
;
1780 /* we found an conditional connection enabled configuration */
1783 domains
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandDomains
);
1784 if (!isA_CFArray(domains
))
1787 domainsCount
= CFArrayGetCount(domains
);
1788 for (domainsIndex
= 0; domainsIndex
< domainsCount
; domainsIndex
++) {
1791 domain
= CFArrayGetValueAtIndex(domains
, domainsIndex
);
1792 if (!isA_CFString(domain
))
1795 if (!catchAllFound
&&
1796 (CFStringCompare(domain
, CFSTR(""), 0) == kCFCompareEqualTo
1797 || CFStringCompare(domain
, CFSTR("."), 0) == kCFCompareEqualTo
)) {
1798 // found a catch all
1799 catchAllFound
= TRUE
;
1800 catchAllService
= serviceIndex
;
1801 catchAllConfig
= configIndex
;
1804 if (domainEndsWithDomain(hostName
, domain
)) {
1805 // found matching configuration
1806 *serviceID
= serviceName
;
1807 CFRetain(*serviceID
);
1808 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1809 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
, hostName
);
1810 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1811 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1813 goto done_selection
;
1820 // config not found, do we have a catchall ?
1821 if (catchAllFound
) {
1822 CFDictionaryRef config
;
1823 CFArrayRef serviceConfigs
;
1824 CFStringRef serviceName
;
1826 serviceName
= CFArrayGetValueAtIndex(serviceNames
, catchAllService
);
1827 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1828 config
= CFArrayGetValueAtIndex(serviceConfigs
, catchAllConfig
);
1830 *serviceID
= serviceName
;
1831 CFRetain(*serviceID
);
1832 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1833 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCNetworkConnectionSelectionOptionOnDemandHostName
, hostName
);
1834 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1835 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1837 goto done_selection
;
1843 CFRelease(serviceNames
);
1845 CFRelease(services
);
1849 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@"), success
? CFSTR("succeeded") : CFSTR("failed"));
1850 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Selection options: %@"), selectionOptions
);
1856 /* we don't have selection options */
1858 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
1859 success
= SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session
, serviceID
);
1861 if (success
&& (*serviceID
!= NULL
)) {
1862 // (2) Get the list of user data for this service ID
1863 CFPropertyListRef userServices
= NULL
;
1866 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
1867 if (userServices
!= NULL
) {
1868 if (isA_CFArray(userServices
)) {
1869 // (4) Get the default set of user options for this service
1870 success
= SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray((CFArrayRef
)userServices
,
1872 if(success
&& (userOptions
!= NULL
)) {
1873 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1876 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Error, userServices are not of type CFArray!"));
1879 CFRelease(userServices
); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
1884 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@, no selection options"), success
? CFSTR("succeeded") : CFSTR("failed"));
1892 //*******************************************************************************************
1893 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
1894 // ----------------------------------------------------
1895 // Try to find the service id to connect
1896 // (1) Start by looking at the last service used in Network Pref / Network menu extra
1897 // (2) If Network Pref / Network menu extra has not been used, find the PPP service
1898 // with the highest ordering
1899 //********************************************************************************************
1901 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1903 Boolean foundService
= FALSE
;
1904 CFPropertyListRef lastServiceSelectedInIC
= NULL
;
1908 // we found the service the user last had open in IC
1909 if (lastServiceSelectedInIC
!= NULL
) {
1910 // make sure its a PPP service
1911 if (SCNetworkConnectionPrivateIsPPPService(session
, lastServiceSelectedInIC
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1912 // make sure the service that we found is valid
1913 CFDictionaryRef dict
;
1916 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1917 kSCDynamicStoreDomainSetup
,
1918 lastServiceSelectedInIC
,
1919 kSCEntNetInterface
);
1920 dict
= SCDynamicStoreCopyValue(session
, key
);
1924 *serviceID
= CFRetain(lastServiceSelectedInIC
);
1925 foundService
= TRUE
;
1928 CFRelease(lastServiceSelectedInIC
);
1931 if (!foundService
) {
1932 foundService
= SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session
, serviceID
);
1935 return foundService
;
1938 //********************************************************************************
1939 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
1940 // -------------------------------------------------------
1941 // Find the highest ordered PPP service in the dynamic store
1942 //********************************************************************************
1944 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1946 CFDictionaryRef dict
= NULL
;
1947 CFStringRef key
= NULL
;
1948 CFArrayRef serviceIDs
= NULL
;
1949 Boolean success
= FALSE
;
1957 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCEntNetIPv4
);
1959 fprintf(stderr
, "Error, Setup Key == NULL!\n");
1963 dict
= SCDynamicStoreCopyValue(session
, key
);
1964 if (!isA_CFDictionary(dict
)) {
1965 fprintf(stderr
, "no global IPv4 entity\n");
1969 serviceIDs
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
); // array of service id's
1970 if (!isA_CFArray(serviceIDs
)) {
1971 fprintf(stderr
, "service order not specified\n");
1975 count
= CFArrayGetCount(serviceIDs
);
1976 for (i
= 0; i
< count
; i
++) {
1977 CFStringRef service
= CFArrayGetValueAtIndex(serviceIDs
, i
);
1979 if (SCNetworkConnectionPrivateIsPPPService(session
, service
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1980 *serviceID
= CFRetain(service
);
1987 if (key
!= NULL
) CFRelease(key
);
1988 if (dict
!= NULL
) CFRelease(dict
);
1993 //********************************************************************************
1994 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
1995 // ---------------------------------------------------------
1996 // Copy over user preferences for a particular service if they exist
1997 //********************************************************************************
1999 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
)
2001 CFIndex count
= CFArrayGetCount(userOptionsArray
);
2004 for (i
= 0; i
< count
; i
++) {
2005 // (1) Find the dictionary
2006 CFPropertyListRef propertyList
= CFArrayGetValueAtIndex(userOptionsArray
, i
);
2008 if (isA_CFDictionary(propertyList
) != NULL
) {
2009 // See if there's a value for dial on demand
2010 CFPropertyListRef value
;
2012 value
= CFDictionaryGetValue((CFDictionaryRef
)propertyList
, k_Dial_Default_Key
);
2013 if (isA_CFBoolean(value
) != NULL
) {
2014 if (CFBooleanGetValue(value
)) {
2015 // we found the default user options
2016 *userOptions
= CFDictionaryCreateCopy(NULL
,
2017 (CFDictionaryRef
)propertyList
);
2027 //********************************************************************************
2028 // SCNetworkConnectionPrivateIsServiceType
2029 // --------------------------------------
2030 // Check and see if the service is a PPP service of the given types
2031 //********************************************************************************
2033 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
)
2035 CFStringRef entityKey
;
2036 Boolean isPPPService
= FALSE
;
2037 Boolean isMatchingSubType
= FALSE
;
2038 CFDictionaryRef serviceDict
;
2040 entityKey
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
2041 kSCDynamicStoreDomainSetup
,
2043 kSCEntNetInterface
);
2044 if (entityKey
== NULL
) {
2048 serviceDict
= SCDynamicStoreCopyValue(session
, entityKey
);
2049 if (serviceDict
!= NULL
) {
2050 if (isA_CFDictionary(serviceDict
)) {
2052 CFStringRef subtype
;
2054 type
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceType
);
2055 if (isA_CFString(type
)) {
2056 isPPPService
= CFEqual(type
, kSCValNetInterfaceTypePPP
);
2059 subtype
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceSubType
);
2060 if (isA_CFString(subtype
)) {
2061 isMatchingSubType
= CFEqual(subtype
, subType1
);
2062 if (!isMatchingSubType
&& subType2
)
2063 isMatchingSubType
= CFEqual(subtype
, subType2
);
2066 CFRelease(serviceDict
);
2068 CFRelease(entityKey
);
2070 return (isPPPService
&& isMatchingSubType
);
2073 //********************************************************************************
2074 // addPasswordFromKeychain
2075 // --------------------------------------
2076 // Get the password and shared secret out of the keychain and add
2077 // them to the PPP and IPSec dictionaries
2078 //********************************************************************************
2080 addPasswordFromKeychain(SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
)
2082 CFPropertyListRef uniqueID
;
2083 CFStringRef password
;
2084 CFStringRef sharedsecret
= NULL
;
2086 /* user options must exist */
2087 if (*userOptions
== NULL
)
2090 /* first, get the unique identifier used to store passwords in the keychain */
2091 uniqueID
= CFDictionaryGetValue(*userOptions
, k_Unique_Id_Key
);
2092 if (!isA_CFString(uniqueID
))
2095 /* first, get the PPP password */
2096 password
= copyPasswordFromKeychain(uniqueID
);
2098 /* then, if necessary, get the IPSec Shared Secret */
2099 if (SCNetworkConnectionPrivateIsPPPService(session
, serviceID
, kSCValNetInterfaceSubTypeL2TP
, 0)) {
2100 CFMutableStringRef uniqueIDSS
;
2102 uniqueIDSS
= CFStringCreateMutableCopy(NULL
, 0, uniqueID
);
2103 CFStringAppend(uniqueIDSS
, CFSTR(".SS"));
2104 sharedsecret
= copyPasswordFromKeychain(uniqueIDSS
);
2105 CFRelease(uniqueIDSS
);
2108 /* did we find our information in the key chain ? */
2109 if ((password
!= NULL
) || (sharedsecret
!= NULL
)) {
2110 CFMutableDictionaryRef newOptions
;
2112 newOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, *userOptions
);
2115 if (password
!= NULL
) {
2116 CFDictionaryRef entity
;
2117 CFMutableDictionaryRef newEntity
;
2119 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetPPP
);
2120 if (isA_CFDictionary(entity
))
2121 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
2123 newEntity
= CFDictionaryCreateMutable(NULL
,
2125 &kCFTypeDictionaryKeyCallBacks
,
2126 &kCFTypeDictionaryValueCallBacks
);
2129 /* set the PPP password */
2130 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPassword
, uniqueID
);
2131 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPasswordEncryption
, kSCValNetPPPAuthPasswordEncryptionKeychain
);
2132 CFRelease(password
);
2134 /* update the PPP entity */
2135 CFDictionarySetValue(newOptions
, kSCEntNetPPP
, newEntity
);
2136 CFRelease(newEntity
);
2139 /* IPSec Shared Secret */
2140 if (sharedsecret
!= NULL
) {
2141 CFDictionaryRef entity
;
2142 CFMutableDictionaryRef newEntity
;
2144 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetIPSec
);
2145 if (isA_CFDictionary(entity
))
2146 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
2148 newEntity
= CFDictionaryCreateMutable(NULL
,
2150 &kCFTypeDictionaryKeyCallBacks
,
2151 &kCFTypeDictionaryValueCallBacks
);
2153 /* set the IPSec Shared Secret */
2154 CFDictionarySetValue(newEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
2155 CFRelease(sharedsecret
);
2157 /* update the IPSec entity */
2158 CFDictionarySetValue(newOptions
, kSCEntNetIPSec
, newEntity
);
2159 CFRelease(newEntity
);
2162 /* update the userOptions dictionary */
2163 CFRelease(*userOptions
);
2164 *userOptions
= CFDictionaryCreateCopy(NULL
, newOptions
);
2165 CFRelease(newOptions
);
2170 #if !TARGET_OS_IPHONE
2171 //********************************************************************************
2172 // copyKeychainEnumerator
2173 // --------------------------------------
2174 // Gather Keychain Enumerator
2175 //********************************************************************************
2177 copyKeychainEnumerator(CFStringRef uniqueIdentifier
)
2180 CFMutableArrayRef itemArray
= NULL
;
2182 SecKeychainSearchRef search
= NULL
;
2184 buf
= _SC_cfstring_to_cstring(uniqueIdentifier
, NULL
, 0, kCFStringEncodingUTF8
);
2186 // search for unique identifier in "svce" attribute
2187 SecKeychainAttribute attributes
[] = {{ kSecServiceItemAttr
,
2188 CFStringGetLength(uniqueIdentifier
),
2192 SecKeychainAttributeList attrList
= { sizeof(attributes
) / sizeof(*attributes
),
2195 result
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attrList
, &search
);
2196 if (result
== noErr
) {
2197 itemArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
2199 while (result
== noErr
) {
2200 SecKeychainItemRef itemFound
= NULL
;
2202 result
= SecKeychainSearchCopyNext(search
, &itemFound
);
2203 if (result
!= noErr
) {
2208 CFArrayAppendValue(itemArray
, itemFound
);
2209 CFRelease(itemFound
);
2215 if (search
) CFRelease(search
);
2216 if (buf
) CFAllocatorDeallocate(NULL
, buf
);
2220 #endif // !TARGET_OS_IPHONE
2222 //********************************************************************************
2223 // copyPasswordFromKeychain
2224 // --------------------------------------
2225 // Given a uniqueID, retrieve the password from the keychain
2226 //********************************************************************************
2228 copyPasswordFromKeychain(CFStringRef uniqueID
)
2230 #if !TARGET_OS_IPHONE
2231 CFArrayRef enumerator
;
2233 CFStringRef password
= NULL
;
2235 enumerator
= copyKeychainEnumerator(uniqueID
);
2236 if (enumerator
== NULL
) {
2237 return NULL
; // if no keychain enumerator
2240 n
= CFArrayGetCount(enumerator
);
2244 SecKeychainItemRef itemRef
;
2247 itemRef
= (SecKeychainItemRef
)CFArrayGetValueAtIndex(enumerator
, 0);
2248 result
= SecKeychainItemCopyContent(itemRef
, // itemRef
2252 (void *)&data
); // outData
2253 if ((result
== noErr
) && (data
!= NULL
) && (dataLen
> 0)) {
2254 password
= CFStringCreateWithBytes(NULL
, data
, dataLen
, kCFStringEncodingUTF8
, TRUE
);
2255 (void) SecKeychainItemFreeContent(NULL
, data
);
2260 CFRelease(enumerator
);
2263 #else // !TARGET_OS_IPHONE
2265 #endif // !TARGET_OS_IPHONE