2 * Copyright (c) 2003-2005 Apple Computer, 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>
34 /* -------------------------------------------------------------------------------------------
35 ------------------------------------------------------------------------------------------- */
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <CoreFoundation/CFRuntime.h>
40 #include <Security/Security.h>
41 #include "dy_framework.h"
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h>
45 #include <SystemConfiguration/SCValidation.h>
47 #include <servers/bootstrap.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
55 #include <sys/ioctl.h>
56 #include <sys/socket.h>
59 #include <ppp/ppp_msg.h>
60 #include <ppp/PPPControllerPriv.h>
61 #include "pppcontroller.h"
62 #include <ppp/pppcontroller_types.h>
65 /* -------------------------------------------------------------------------------------------
66 ------------------------------------------------------------------------------------------- */
70 /* base CFType information */
74 CFStringRef serviceID
;
76 /* ref to PPP controller for control messages */
77 mach_port_t session_port
;
79 /* ref to PPP controller for notification messages */
80 CFMachPortRef notify_port
;
82 /* run loop source, callout, context, rl scheduling info */
83 CFRunLoopSourceRef rls
;
84 SCNetworkConnectionCallBack rlsFunction
;
85 SCNetworkConnectionContext rlsContext
;
86 CFMutableArrayRef rlList
;
91 } SCNetworkConnectionPrivate
, *SCNetworkConnectionPrivateRef
;
93 /* -------------------------------------------------------------------------------------------
94 ------------------------------------------------------------------------------------------- */
96 static __inline__ CFTypeRef
97 isA_SCNetworkConnection(CFTypeRef obj
)
99 return (isA_CFType(obj
, SCNetworkConnectionGetTypeID()));
102 /* -------------------------------------------------------------------------------------------
103 ------------------------------------------------------------------------------------------- */
106 __SCNetworkConnectionCopyDescription(CFTypeRef cf
)
108 CFAllocatorRef allocator
= CFGetAllocator(cf
);
109 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
110 CFMutableStringRef result
;
112 result
= CFStringCreateMutable(allocator
, 0);
113 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkConnection, %p [%p]> {\n"), cf
, allocator
);
114 CFStringAppendFormat(result
, NULL
, CFSTR(" serviceID = %@ \n"), connectionPrivate
->serviceID
);
115 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
120 /* -------------------------------------------------------------------------------------------
121 ------------------------------------------------------------------------------------------- */
124 __SCNetworkConnectionDeallocate(CFTypeRef cf
)
126 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
128 if (connectionPrivate
->debug
) {
129 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionDeallocate (0x%x)"), connectionPrivate
);
132 /* release resources */
133 if (connectionPrivate
->rlList
!= NULL
) {
134 CFRunLoopSourceInvalidate(connectionPrivate
->rls
);
135 CFRelease(connectionPrivate
->rls
);
136 CFRelease(connectionPrivate
->rlList
);
139 if (connectionPrivate
->notify_port
!= NULL
) {
140 CFMachPortInvalidate(connectionPrivate
->notify_port
);
141 CFRelease(connectionPrivate
->notify_port
);
144 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
)
145 mach_port_destroy(mach_task_self(), connectionPrivate
->session_port
);
147 if (connectionPrivate
->rlsContext
.release
!= NULL
)
148 (*connectionPrivate
->rlsContext
.release
)(connectionPrivate
->rlsContext
.info
);
150 if (connectionPrivate
->serviceID
)
151 CFRelease(connectionPrivate
->serviceID
);
156 /* -------------------------------------------------------------------------------------------
157 ------------------------------------------------------------------------------------------- */
159 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
161 static CFTypeID __kSCNetworkConnectionTypeID
= _kCFRuntimeNotATypeID
;
163 static const CFRuntimeClass __SCNetworkConnectionClass
= {
165 "SCNetworkConnection", // className
168 __SCNetworkConnectionDeallocate
, // dealloc
171 NULL
, // copyFormattingDesc
172 __SCNetworkConnectionCopyDescription
// copyDebugDesc
175 /* -------------------------------------------------------------------------------------------
176 ------------------------------------------------------------------------------------------- */
179 __SCNetworkConnectionInitialize(void)
181 __kSCNetworkConnectionTypeID
= _CFRuntimeRegisterClass(&__SCNetworkConnectionClass
);
185 /* -------------------------------------------------------------------------------------------
186 ------------------------------------------------------------------------------------------- */
188 static SCNetworkConnectionStatus
189 __SCNetworkConnectionConvertStatus (int state
)
191 SCNetworkConnectionStatus status
= kSCNetworkConnectionDisconnected
;
195 case PPP_CONNECTLINK
:
197 case PPP_AUTHENTICATE
:
201 status
= kSCNetworkConnectionConnecting
;
204 case PPP_DISCONNECTLINK
:
205 status
= kSCNetworkConnectionDisconnecting
;
209 status
= kSCNetworkConnectionConnected
;
215 status
= kSCNetworkConnectionDisconnected
;
220 /* -------------------------------------------------------------------------------------------
221 ------------------------------------------------------------------------------------------- */
224 __SCNetworkConnectionCallBack(CFMachPortRef port
, void * msg
, CFIndex size
, void * info
)
226 mach_msg_empty_rcv_t
* buf
= msg
;
227 SCNetworkConnectionRef connection
= (SCNetworkConnectionRef
)info
;
228 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
230 void (*context_release
)(const void *);
231 int error
= kSCStatusFailed
;
232 mach_msg_id_t msgid
= buf
->header
.msgh_id
;
233 int phase
= PPP_IDLE
;
234 SCNetworkConnectionCallBack rlsFunction
;
235 kern_return_t status
;
236 SCNetworkConnectionStatus scstatus
;
238 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
239 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionCallBack: PPPController server died"));
241 status
= pppcontroller_getstatus(connectionPrivate
->session_port
, &phase
, &error
);
244 if (connectionPrivate
->rls
== NULL
) {
248 rlsFunction
= connectionPrivate
->rlsFunction
;
249 if (rlsFunction
== NULL
) {
253 if ((connectionPrivate
->rlsContext
.retain
!= NULL
) && (connectionPrivate
->rlsContext
.info
!= NULL
)) {
254 context_info
= (void *)(*connectionPrivate
->rlsContext
.retain
)(connectionPrivate
->rlsContext
.info
);
255 context_release
= connectionPrivate
->rlsContext
.release
;
257 context_info
= connectionPrivate
->rlsContext
.info
;
258 context_release
= NULL
;
261 scstatus
= __SCNetworkConnectionConvertStatus(phase
);
263 (*rlsFunction
)(connection
, scstatus
, context_info
);
264 if ((context_release
!= NULL
) && (context_info
!= NULL
)) {
265 (*context_release
)(context_info
);
271 /* -------------------------------------------------------------------------------------------
272 ------------------------------------------------------------------------------------------- */
273 static SCNetworkConnectionPrivateRef
274 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator
,
275 CFStringRef serviceID
,
276 SCNetworkConnectionCallBack callout
,
277 SCNetworkConnectionContext
*context
)
280 SCNetworkConnectionPrivateRef connectionPrivate
= NULL
;
283 CFDataRef dataRef
= NULL
;
285 int error
= kSCStatusFailed
;
286 CFMachPortContext mach_context
= {0, NULL
, NULL
, NULL
, NULL
};
287 mach_port_t notify_port
= MACH_PORT_NULL
;
288 mach_port_t port_old
;
291 kern_return_t status
;
292 mach_port_t unpriv_bootstrap_port
;
294 /* initialize runtime */
295 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
297 if ((bootstrap_status (bootstrap_port
, PPPCONTROLLER_SERVER
, &active
) != BOOTSTRAP_SUCCESS
) ||
298 (bootstrap_look_up(bootstrap_port
, PPPCONTROLLER_SERVER
, &server
) != BOOTSTRAP_SUCCESS
)) {
299 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("PPP Controller server not found"));
303 /* allocate NetworkConnection */
304 size
= sizeof(SCNetworkConnectionPrivate
) - sizeof(CFRuntimeBase
);
305 connectionPrivate
= (SCNetworkConnectionPrivateRef
)_CFRuntimeCreateInstance(allocator
, __kSCNetworkConnectionTypeID
, size
, NULL
);
306 if (connectionPrivate
== NULL
) {
310 /* zero the data structure */
311 bzero(((u_char
*)connectionPrivate
)+sizeof(CFRuntimeBase
), size
);
313 /* save the serviceID */
314 connectionPrivate
->serviceID
= CFStringCreateCopy(NULL
, serviceID
);
316 /* get the debug environment variable */
317 envdebug
= getenv("PPPDebug");
319 if (sscanf(envdebug
, "%d", &connectionPrivate
->debug
) != 1)
320 connectionPrivate
->debug
= 1; /* PPPDebug value is invalid, set debug to 1 */
323 if (callout
!= NULL
) {
324 connectionPrivate
->rlsFunction
= callout
;
326 mach_context
.info
= (void*)connectionPrivate
;
327 connectionPrivate
->notify_port
= CFMachPortCreate(NULL
, __SCNetworkConnectionCallBack
, &mach_context
, NULL
);
328 if (connectionPrivate
->notify_port
== NULL
) {
332 notify_port
= CFMachPortGetPort(connectionPrivate
->notify_port
);
333 status
= mach_port_request_notification(mach_task_self(),
334 notify_port
, MACH_NOTIFY_NO_SENDERS
, 1,
335 notify_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &port_old
);
336 if (status
!= KERN_SUCCESS
) {
342 bcopy(context
, &connectionPrivate
->rlsContext
, sizeof(SCNetworkConnectionContext
));
343 if (context
->retain
!= NULL
) {
344 connectionPrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
348 if (!_SCSerializeString(serviceID
, &dataRef
, &data
, &dataLen
)) {
352 status
= bootstrap_unprivileged(bootstrap_port
, &unpriv_bootstrap_port
);
353 if (status
!= BOOTSTRAP_SUCCESS
) {
357 status
= pppcontroller_attach(server
, data
, dataLen
, unpriv_bootstrap_port
, notify_port
,
358 &connectionPrivate
->session_port
, &error
);
360 mach_port_deallocate(mach_task_self(), unpriv_bootstrap_port
);
364 if (status
!= KERN_SUCCESS
) {
368 if (error
!= kSCStatusOK
) {
372 if (connectionPrivate
->debug
) {
373 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCreate (0x%x) succeeded for service ID: %@"), connectionPrivate
, serviceID
);
376 /* success, return the connection reference */
377 return connectionPrivate
;
382 /* failure, clean up and leave */
383 if (connectionPrivate
!= NULL
) {
384 if (connectionPrivate
->debug
)
385 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCreate (0x%x) failed for service ID: %@"), connectionPrivate
, serviceID
);
386 CFRelease(connectionPrivate
);
389 if (dataRef
) CFRelease(dataRef
);
394 /* -------------------------------------------------------------------------------------------
395 ------------------------------------------------------------------------------------------- */
398 SCNetworkConnectionGetTypeID(void) {
399 pthread_once(&initialized
, __SCNetworkConnectionInitialize
); /* initialize runtime */
400 return __kSCNetworkConnectionTypeID
;
403 /* -------------------------------------------------------------------------------------------
404 ------------------------------------------------------------------------------------------- */
406 SCNetworkConnectionRef
407 SCNetworkConnectionCreateWithServiceID(CFAllocatorRef allocator
,
408 CFStringRef serviceID
,
409 SCNetworkConnectionCallBack callout
,
410 SCNetworkConnectionContext
*context
)
412 SCNetworkConnectionPrivateRef connectionPrivate
;
414 if (!isA_CFString(serviceID
)) {
415 _SCErrorSet(kSCStatusInvalidArgument
);
420 connectionPrivate
= __SCNetworkConnectionCreatePrivate(allocator
, serviceID
, callout
, context
);
422 return (SCNetworkConnectionRef
)connectionPrivate
;
425 /* -------------------------------------------------------------------------------------------
426 ------------------------------------------------------------------------------------------- */
429 SCNetworkConnectionCopyServiceID(SCNetworkConnectionRef connection
)
431 if (!isA_SCNetworkConnection(connection
)) {
432 _SCErrorSet(kSCStatusInvalidArgument
);
436 return CFRetain(((SCNetworkConnectionPrivateRef
)connection
)->serviceID
);
439 /* -------------------------------------------------------------------------------------------
440 ------------------------------------------------------------------------------------------- */
443 SCNetworkConnectionCopyStatistics(SCNetworkConnectionRef connection
)
445 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
446 xmlDataOut_t data
= NULL
;
447 mach_msg_type_number_t datalen
;
448 int error
= kSCStatusFailed
;
449 CFPropertyListRef statistics
= NULL
;
450 kern_return_t status
;
452 if (!isA_SCNetworkConnection(connection
)) {
453 _SCErrorSet(kSCStatusInvalidArgument
);
457 status
= pppcontroller_copystatistics(connectionPrivate
->session_port
, &data
, &datalen
, &error
);
458 if (status
!= KERN_SUCCESS
) {
462 if (error
!= kSCStatusOK
) {
466 if ((data
== NULL
) ||
467 !_SCUnserialize(&statistics
, NULL
, data
, datalen
) ||
468 !isA_CFDictionary(statistics
)) {
476 if (statistics
) CFRelease(statistics
);
481 /* -------------------------------------------------------------------------------------------
482 ------------------------------------------------------------------------------------------- */
484 SCNetworkConnectionStatus
485 SCNetworkConnectionGetStatus(SCNetworkConnectionRef connection
)
487 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
488 int error
= kSCStatusFailed
;
490 SCNetworkConnectionStatus scstatus
;
491 kern_return_t status
;
493 if (!isA_SCNetworkConnection(connection
)) {
494 _SCErrorSet(kSCStatusInvalidArgument
);
495 return kSCNetworkConnectionInvalid
;
498 status
= pppcontroller_getstatus(connectionPrivate
->session_port
, &phase
, &error
);
499 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
500 return kSCNetworkConnectionDisconnected
;
503 scstatus
= __SCNetworkConnectionConvertStatus(phase
);
507 /* -------------------------------------------------------------------------------------------
508 ------------------------------------------------------------------------------------------- */
511 SCNetworkConnectionCopyExtendedStatus(SCNetworkConnectionRef connection
)
513 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
514 xmlDataOut_t data
= NULL
;
515 mach_msg_type_number_t datalen
;
516 int error
= kSCStatusFailed
;
517 CFPropertyListRef extstatus
= NULL
;
518 kern_return_t status
;
520 if (!isA_SCNetworkConnection(connection
)) {
521 _SCErrorSet(kSCStatusInvalidArgument
);
525 status
= pppcontroller_copyextendedstatus(connectionPrivate
->session_port
, &data
, &datalen
, &error
);
526 if (status
!= KERN_SUCCESS
) {
530 if (error
!= kSCStatusOK
) {
534 if ((data
== NULL
) ||
535 !_SCUnserialize(&extstatus
, NULL
, data
, datalen
) ||
536 !isA_CFDictionary(extstatus
)) {
544 if (extstatus
) CFRelease(extstatus
);
549 /* -------------------------------------------------------------------------------------------
550 ------------------------------------------------------------------------------------------- */
553 SCNetworkConnectionStart(SCNetworkConnectionRef connection
,
554 CFDictionaryRef userOptions
,
557 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
558 CFDataRef dataref
= NULL
;
561 int error
= kSCStatusFailed
;
562 kern_return_t status
;
564 if (!isA_SCNetworkConnection(connection
)) {
565 _SCErrorSet(kSCStatusInvalidArgument
);
569 if (connectionPrivate
->debug
) {
570 CFMutableDictionaryRef mdict
= NULL
, mdict1
;
571 CFDictionaryRef dict
;
573 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x)"), connectionPrivate
);
576 /* special code to remove secret information */
577 mdict
= CFDictionaryCreateMutableCopy(0, 0, userOptions
);
579 dict
= CFDictionaryGetValue(mdict
, kSCEntNetPPP
);
580 if (isA_CFDictionary(dict
)) {
581 mdict1
= CFDictionaryCreateMutableCopy(0, 0, dict
);
583 CFDictionaryReplaceValue(mdict1
, kSCPropNetPPPAuthPassword
, CFSTR("******"));
584 CFDictionarySetValue(mdict
, kSCEntNetPPP
, mdict1
);
589 dict
= CFDictionaryGetValue(mdict
, kSCEntNetL2TP
);
590 if (isA_CFDictionary(dict
)) {
591 mdict1
= CFDictionaryCreateMutableCopy(0, 0, dict
);
593 CFDictionaryReplaceValue(mdict1
, kSCPropNetL2TPIPSecSharedSecret
, CFSTR("******"));
594 CFDictionarySetValue(mdict
, kSCEntNetL2TP
, mdict1
);
599 dict
= CFDictionaryGetValue(mdict
, kSCEntNetIPSec
);
600 if (isA_CFDictionary(dict
)) {
601 mdict1
= CFDictionaryCreateMutableCopy(0, 0, dict
);
603 CFDictionaryReplaceValue(mdict1
, kSCPropNetIPSecSharedSecret
, CFSTR("******"));
604 CFDictionarySetValue(mdict
, kSCEntNetIPSec
, mdict1
);
611 SCLog(TRUE
, LOG_DEBUG
, CFSTR("User options: %@"), mdict
);
616 if (userOptions
&& !_SCSerialize(userOptions
, &dataref
, &data
, &datalen
)) {
620 status
= pppcontroller_start(connectionPrivate
->session_port
, data
, datalen
, linger
, &error
);
621 if (status
!= KERN_SUCCESS
) {
630 if (connectionPrivate
->debug
)
631 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x), return: %d"), connectionPrivate
, error
);
633 if (error
!= kSCStatusOK
) {
637 /* connection is now started */
642 if (dataref
) CFRelease(dataref
);
647 /* -------------------------------------------------------------------------------------------
648 ------------------------------------------------------------------------------------------- */
651 SCNetworkConnectionStop(SCNetworkConnectionRef connection
,
652 Boolean forceDisconnect
)
654 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
655 int error
= kSCStatusFailed
;
656 kern_return_t status
;
658 if (!isA_SCNetworkConnection(connection
)) {
659 _SCErrorSet(kSCStatusInvalidArgument
);
663 if (connectionPrivate
->debug
)
664 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x)"), connectionPrivate
);
666 status
= pppcontroller_stop(connectionPrivate
->session_port
, forceDisconnect
, &error
);
667 if (status
!= KERN_SUCCESS
) {
671 if (connectionPrivate
->debug
)
672 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x), return: %d"), connectionPrivate
, error
);
674 if (error
!= kSCStatusOK
) {
678 /* connection is now disconnecting */
687 /* -------------------------------------------------------------------------------------------
688 ------------------------------------------------------------------------------------------- */
691 SCNetworkConnectionSuspend(SCNetworkConnectionRef connection
)
693 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
694 int error
= kSCStatusFailed
;
695 kern_return_t status
;
697 if (!isA_SCNetworkConnection(connection
)) {
698 _SCErrorSet(kSCStatusInvalidArgument
);
702 if (connectionPrivate
->debug
)
703 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x)"), connectionPrivate
);
705 status
= pppcontroller_suspend(connectionPrivate
->session_port
, &error
);
706 if (status
!= KERN_SUCCESS
) {
710 if (connectionPrivate
->debug
)
711 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x), return: %d"), connectionPrivate
, error
);
713 if (error
!= kSCStatusOK
) {
717 /* connection is now suspended */
726 /* -------------------------------------------------------------------------------------------
727 ------------------------------------------------------------------------------------------- */
730 SCNetworkConnectionResume(SCNetworkConnectionRef connection
)
732 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
733 int error
= kSCStatusFailed
;
734 kern_return_t status
;
736 if (!isA_SCNetworkConnection(connection
)) {
737 _SCErrorSet(kSCStatusInvalidArgument
);
741 if (connectionPrivate
->debug
)
742 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x)"), connectionPrivate
);
744 status
= pppcontroller_resume(connectionPrivate
->session_port
, &error
);
745 if (status
!= KERN_SUCCESS
) {
749 if (connectionPrivate
->debug
)
750 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x), return: %d"), connectionPrivate
, error
);
752 if (error
!= kSCStatusOK
) {
756 /* connection is now resume */
765 /* -------------------------------------------------------------------------------------------
766 ------------------------------------------------------------------------------------------- */
769 SCNetworkConnectionCopyUserOptions(SCNetworkConnectionRef connection
)
771 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
772 xmlDataOut_t data
= NULL
;
773 mach_msg_type_number_t datalen
;
774 int error
= kSCStatusFailed
;
775 kern_return_t status
;
776 CFPropertyListRef userOptions
= NULL
;
778 if (!isA_SCNetworkConnection(connection
)) {
779 _SCErrorSet(kSCStatusInvalidArgument
);
783 status
= pppcontroller_copyuseroptions(connectionPrivate
->session_port
, &data
, &datalen
, &error
);
784 if (status
!= KERN_SUCCESS
) {
788 if (error
!= kSCStatusOK
) {
792 // no data were used, return an empty dictionary
794 CFDictionaryRef dict
;
796 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
798 _SCErrorSet(kSCStatusFailed
); // XXX
803 if (!_SCUnserialize(&userOptions
, NULL
, data
, datalen
) ||
804 !isA_CFDictionary(userOptions
)) {
812 if (userOptions
) CFRelease(userOptions
);
817 /* -------------------------------------------------------------------------------------------
818 ------------------------------------------------------------------------------------------- */
821 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
822 CFRunLoopRef runLoop
,
823 CFStringRef runLoopMode
)
825 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
826 int error
= kSCStatusFailed
;
827 kern_return_t status
;
829 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
830 _SCErrorSet(kSCStatusInvalidArgument
);
834 if (connectionPrivate
->rlsFunction
== NULL
) {
835 _SCErrorSet(kSCStatusInvalidArgument
);
839 if ((connectionPrivate
->rlList
!= NULL
) &&
840 _SC_isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
841 /* already scheduled */
842 _SCErrorSet(kSCStatusFailed
);
846 if (connectionPrivate
->rlList
== NULL
) {
847 status
= pppcontroller_notification(connectionPrivate
->session_port
, 1, &error
);
848 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
853 connectionPrivate
->rls
= CFMachPortCreateRunLoopSource(NULL
, connectionPrivate
->notify_port
, 0);
854 connectionPrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
857 CFRunLoopAddSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
858 _SC_schedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
);
863 /* -------------------------------------------------------------------------------------------
864 ------------------------------------------------------------------------------------------- */
867 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
868 CFRunLoopRef runLoop
,
869 CFStringRef runLoopMode
)
871 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
872 int error
= kSCStatusFailed
;
873 kern_return_t status
;
875 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
876 _SCErrorSet(kSCStatusInvalidArgument
);
880 if ((connectionPrivate
->rlList
== NULL
) ||
881 !_SC_unschedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
, FALSE
)) {
882 /* if not currently scheduled */
883 _SCErrorSet(kSCStatusFailed
);
887 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
889 if (CFArrayGetCount(connectionPrivate
->rlList
) == 0) {
890 CFRelease(connectionPrivate
->rls
);
891 connectionPrivate
->rls
= NULL
;
892 CFRelease(connectionPrivate
->rlList
);
893 connectionPrivate
->rlList
= NULL
;
895 status
= pppcontroller_notification(connectionPrivate
->session_port
, 0, &error
);
896 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
906 //************************* USER LEVEL DIAL API **********************************
909 #define k_NetworkConnect_Notification "com.apple.networkConnect"
910 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
911 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
913 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
914 #define k_Last_Service_Id_Key CFSTR("ServiceID")
915 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
918 /* Private Prototypes */
919 static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
920 static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
921 static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
);
922 static Boolean
SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
);
923 static void addPasswordFromKeychain (SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
);
924 static CFStringRef
copyPasswordFromKeychain (CFStringRef uniqueID
);
925 static CFArrayRef
copyKeychainEnumerator (CFStringRef uniqueIdentifier
);
927 static int notify_userprefs_token
= -1;
930 * return TRUE if domain1 ends with domain2, and will check for trailing "."
933 domainEndsWithDomain(CFStringRef domain1
, CFStringRef domain2
)
937 CFStringRef s1
= NULL
;
938 Boolean s1_created
= FALSE
;
939 CFStringRef s2
= NULL
;
940 Boolean s2_created
= FALSE
;
942 if (CFStringHasSuffix(domain1
, CFSTR("."))) {
944 range
.length
= CFStringGetLength(domain1
) - 1;
945 s1
= CFStringCreateWithSubstring(NULL
, domain1
, range
);
954 if (CFStringHasSuffix(domain2
, CFSTR("."))) {
956 range
.length
= CFStringGetLength(domain2
) - 1;
957 s2
= CFStringCreateWithSubstring(NULL
, domain2
, range
);
966 ret
= CFStringHasSuffix(s1
, s2
);
970 if (s1_created
) CFRelease(s1
);
971 if (s2_created
) CFRelease(s2
);
977 SCNetworkConnectionCopyUserPreferences(CFDictionaryRef selectionOptions
,
978 CFStringRef
*serviceID
,
979 CFDictionaryRef
*userOptions
)
984 SCDynamicStoreRef session
;
985 Boolean success
= FALSE
;
989 envdebug
= getenv("PPPDebug");
991 if (sscanf(envdebug
, "%d", &debug
) != 1)
992 debug
= 1; /* PPPDebug value is invalid, set debug to 1 */
995 if (notify_userprefs_token
== -1) {
996 status
= notify_register_check(k_NetworkConnect_Notification
, ¬ify_userprefs_token
);
997 if (status
!= NOTIFY_STATUS_OK
)
998 notify_userprefs_token
= -1;
1001 notify_check(notify_userprefs_token
, &prefsChanged
);
1005 if (notify_userprefs_token
!= -1)
1006 notify_check(notify_userprefs_token
, &prefsChanged
);
1009 // NOTE: we are currently ignoring selectionOptions
1012 *userOptions
= NULL
;
1014 session
= SCDynamicStoreCreate(NULL
, CFSTR("SCNetworkConnection"), NULL
, NULL
);
1015 if (session
== NULL
) {
1016 fprintf(stderr
, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
1020 if (selectionOptions
) {
1021 Boolean catchAllFound
= FALSE
;
1022 CFIndex catchAllService
= 0;
1023 CFIndex catchAllConfig
= 0;
1024 CFStringRef hostName
= NULL
;
1025 CFStringRef priority
= NULL
;
1026 CFArrayRef serviceNames
= NULL
;
1027 CFDictionaryRef services
= NULL
;
1028 CFIndex serviceIndex
;
1029 CFIndex servicesCount
;
1031 hostName
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandHostName
);
1032 if (!isA_CFString(hostName
))
1035 // can't select anything
1036 if (hostName
== NULL
)
1037 goto done_selection
;
1039 priority
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandPriority
);
1040 if (!isA_CFString(priority
))
1041 priority
= kSCValNetPPPOnDemandPriorityDefault
;
1044 if (!isA_CFArray(serviceNames
))
1045 goto done_selection
;
1048 if (!isA_CFDictionary(services
))
1049 goto done_selection
;
1051 servicesCount
= CFArrayGetCount(serviceNames
);
1052 for (serviceIndex
= 0; serviceIndex
< servicesCount
; serviceIndex
++) {
1053 CFIndex configIndex
;
1054 CFIndex configsCount
;
1055 CFArrayRef serviceConfigs
;
1056 CFStringRef serviceName
;
1059 serviceName
= CFArrayGetValueAtIndex(serviceNames
, serviceIndex
);
1060 if (!isA_CFString(serviceName
))
1063 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1064 if (!isA_CFArray(serviceConfigs
))
1067 configsCount
= CFArrayGetCount(serviceConfigs
);
1068 for (configIndex
= 0; configIndex
< configsCount
; configIndex
++) {
1069 CFNumberRef autodial
;
1070 CFDictionaryRef config
;
1071 CFDictionaryRef pppConfig
;
1073 config
= CFArrayGetValueAtIndex(serviceConfigs
, configIndex
);
1074 if (!isA_CFDictionary(config
))
1077 pppConfig
= CFDictionaryGetValue(config
, kSCEntNetPPP
);
1078 if (!isA_CFDictionary(pppConfig
))
1081 autodial
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandEnabled
);
1082 if (!isA_CFNumber(autodial
))
1085 CFNumberGetValue(autodial
, kCFNumberIntType
, &val
);
1087 CFArrayRef autoDomains
;
1088 CFIndex domainIndex
;
1089 CFIndex domainsCount
;
1091 /* we found an conditional connection enabled configuration */
1094 autoDomains
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandDomains
);
1095 if (!isA_CFArray(autoDomains
))
1098 domainsCount
= CFArrayGetCount(autoDomains
);
1099 for (domainIndex
= 0; domainIndex
< domainsCount
; domainIndex
++) {
1102 domain
= CFArrayGetValueAtIndex(autoDomains
, domainIndex
);
1103 if (!isA_CFString(domain
))
1106 if (!catchAllFound
&&
1107 (CFStringCompare(domain
, CFSTR(""), 0) == kCFCompareEqualTo
1108 || CFStringCompare(domain
, CFSTR("."), 0) == kCFCompareEqualTo
)) {
1109 // found a catch all
1110 catchAllFound
= TRUE
;
1111 catchAllService
= serviceIndex
;
1112 catchAllConfig
= configIndex
;
1115 if (domainEndsWithDomain(hostName
, domain
)) {
1116 // found matching configuration
1117 *serviceID
= serviceName
;
1118 CFRetain(*serviceID
);
1119 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1120 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandHostName
, hostName
);
1121 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1122 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1124 goto done_selection
;
1131 // config not found, do we have a catchall ?
1132 if (catchAllFound
) {
1133 CFDictionaryRef config
;
1134 CFArrayRef serviceConfigs
;
1135 CFStringRef serviceName
;
1137 serviceName
= CFArrayGetValueAtIndex(serviceNames
, catchAllService
);
1138 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1139 config
= CFArrayGetValueAtIndex(serviceConfigs
, catchAllConfig
);
1141 *serviceID
= serviceName
;
1142 CFRetain(*serviceID
);
1143 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1144 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandHostName
, hostName
);
1145 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1146 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1148 goto done_selection
;
1154 CFRelease(serviceNames
);
1156 CFRelease(services
);
1160 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@"), success
? CFSTR("succeeded") : CFSTR("failed"));
1161 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Selection options: %@"), selectionOptions
);
1167 /* we don't have selection options */
1169 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
1170 success
= SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session
, serviceID
);
1172 if (success
&& (*serviceID
!= NULL
)) {
1173 // (2) Get the list of user data for this service ID
1174 CFPropertyListRef userServices
= NULL
;
1177 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
1178 if (userServices
!= NULL
) {
1179 if (isA_CFArray(userServices
)) {
1180 // (4) Get the default set of user options for this service
1181 success
= SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray((CFArrayRef
)userServices
,
1183 if(success
&& (userOptions
!= NULL
)) {
1184 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1187 fprintf(stderr
, "Error, userServices are not of type CFArray!\n");
1190 CFRelease(userServices
); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
1195 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@, no selection options"), success
? CFSTR("succeeded") : CFSTR("failed"));
1203 //*******************************************************************************************
1204 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
1205 // ----------------------------------------------------
1206 // Try to find the service id to connect
1207 // (1) Start by looking at the last service used in Internet Connect
1208 // (2) If Internet Connect has not been used, find the PPP service with the highest ordering
1209 //********************************************************************************************
1211 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1213 Boolean foundService
= FALSE
;
1214 CFPropertyListRef lastServiceSelectedInIC
= NULL
;
1218 // we found the service the user last had open in IC
1219 if (lastServiceSelectedInIC
!= NULL
) {
1220 // make sure its a PPP service
1221 if (SCNetworkConnectionPrivateIsPPPService(session
, lastServiceSelectedInIC
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1222 // make sure the service that we found is valid
1223 CFDictionaryRef dict
;
1226 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1227 kSCDynamicStoreDomainSetup
,
1228 lastServiceSelectedInIC
,
1229 kSCEntNetInterface
);
1230 dict
= SCDynamicStoreCopyValue(session
, key
);
1234 *serviceID
= CFRetain(lastServiceSelectedInIC
);
1235 foundService
= TRUE
;
1238 CFRelease(lastServiceSelectedInIC
);
1241 if (!foundService
) {
1242 foundService
= SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session
, serviceID
);
1245 return foundService
;
1248 //********************************************************************************
1249 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
1250 // -------------------------------------------------------
1251 // Find the highest ordered PPP service in the dynamic store
1252 //********************************************************************************
1254 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1256 CFDictionaryRef dict
= NULL
;
1257 CFStringRef key
= NULL
;
1258 CFArrayRef serviceIDs
= NULL
;
1259 Boolean success
= FALSE
;
1267 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCEntNetIPv4
);
1269 fprintf(stderr
, "Error, Setup Key == NULL!\n");
1273 dict
= SCDynamicStoreCopyValue(session
, key
);
1274 if (!isA_CFDictionary(dict
)) {
1275 fprintf(stderr
, "no global IPv4 entity\n");
1279 serviceIDs
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
); // array of service id's
1280 if (!isA_CFArray(serviceIDs
)) {
1281 fprintf(stderr
, "service order not specified\n");
1285 count
= CFArrayGetCount(serviceIDs
);
1286 for (i
= 0; i
< count
; i
++) {
1287 CFStringRef service
= CFArrayGetValueAtIndex(serviceIDs
, i
);
1289 if (SCNetworkConnectionPrivateIsPPPService(session
, service
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1290 *serviceID
= CFRetain(service
);
1297 if (key
!= NULL
) CFRelease(key
);
1298 if (dict
!= NULL
) CFRelease(dict
);
1303 //********************************************************************************
1304 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
1305 // ---------------------------------------------------------
1306 // Copy over user preferences for a particular service if they exist
1307 //********************************************************************************
1309 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
)
1311 CFIndex count
= CFArrayGetCount(userOptionsArray
);
1314 for (i
= 0; i
< count
; i
++) {
1315 // (1) Find the dictionary
1316 CFPropertyListRef propertyList
= CFArrayGetValueAtIndex(userOptionsArray
, i
);
1318 if (isA_CFDictionary(propertyList
) != NULL
) {
1319 // See if there's a value for dial on demand
1320 CFPropertyListRef value
;
1322 value
= CFDictionaryGetValue((CFDictionaryRef
)propertyList
, k_Dial_Default_Key
);
1323 if (isA_CFBoolean(value
) != NULL
) {
1324 if (CFBooleanGetValue(value
)) {
1325 // we found the default user options
1326 *userOptions
= CFDictionaryCreateCopy(NULL
,
1327 (CFDictionaryRef
)propertyList
);
1337 //********************************************************************************
1338 // SCNetworkConnectionPrivateIsServiceType
1339 // --------------------------------------
1340 // Check and see if the service is a PPP service of the given types
1341 //********************************************************************************
1343 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
)
1345 CFStringRef entityKey
;
1346 Boolean isPPPService
= FALSE
;
1347 Boolean isMatchingSubType
= FALSE
;
1348 CFDictionaryRef serviceDict
;
1350 entityKey
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1351 kSCDynamicStoreDomainSetup
,
1353 kSCEntNetInterface
);
1354 if (entityKey
== NULL
) {
1358 serviceDict
= SCDynamicStoreCopyValue(session
, entityKey
);
1359 if (serviceDict
!= NULL
) {
1360 if (isA_CFDictionary(serviceDict
)) {
1362 CFStringRef subtype
;
1364 type
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceType
);
1365 if (isA_CFString(type
)) {
1366 isPPPService
= CFEqual(type
, kSCValNetInterfaceTypePPP
);
1369 subtype
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceSubType
);
1370 if (isA_CFString(subtype
)) {
1371 isMatchingSubType
= CFEqual(subtype
, subType1
);
1372 if (!isMatchingSubType
&& subType2
)
1373 isMatchingSubType
= CFEqual(subtype
, subType2
);
1376 CFRelease(serviceDict
);
1378 CFRelease(entityKey
);
1380 return (isPPPService
&& isMatchingSubType
);
1383 //********************************************************************************
1384 // addPasswordFromKeychain
1385 // --------------------------------------
1386 // Get the password and shared secret out of the keychain and add
1387 // them to the PPP and IPSec dictionaries
1388 //********************************************************************************
1390 addPasswordFromKeychain(SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
)
1392 CFPropertyListRef uniqueID
;
1393 CFStringRef password
;
1394 CFStringRef sharedsecret
= NULL
;
1396 /* user options must exist */
1397 if (*userOptions
== NULL
)
1400 /* first, get the unique identifier used to store passwords in the keychain */
1401 uniqueID
= CFDictionaryGetValue(*userOptions
, k_Unique_Id_Key
);
1402 if (!isA_CFString(uniqueID
))
1405 /* first, get the PPP password */
1406 password
= copyPasswordFromKeychain(uniqueID
);
1408 /* then, if necessary, get the IPSec Shared Secret */
1409 if (SCNetworkConnectionPrivateIsPPPService(session
, serviceID
, kSCValNetInterfaceSubTypeL2TP
, 0)) {
1410 CFMutableStringRef uniqueIDSS
;
1412 uniqueIDSS
= CFStringCreateMutableCopy(NULL
, 0, uniqueID
);
1413 CFStringAppend(uniqueIDSS
, CFSTR(".SS"));
1414 sharedsecret
= copyPasswordFromKeychain(uniqueIDSS
);
1415 CFRelease(uniqueIDSS
);
1418 /* did we find our information in the key chain ? */
1419 if ((password
!= NULL
) || (sharedsecret
!= NULL
)) {
1420 CFMutableDictionaryRef newOptions
;
1422 newOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, *userOptions
);
1425 if (password
!= NULL
) {
1426 CFDictionaryRef entity
;
1427 CFMutableDictionaryRef newEntity
;
1429 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetPPP
);
1430 if (isA_CFDictionary(entity
))
1431 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1433 newEntity
= CFDictionaryCreateMutable(NULL
,
1435 &kCFTypeDictionaryKeyCallBacks
,
1436 &kCFTypeDictionaryValueCallBacks
);
1439 /* set the PPP password */
1440 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPassword
, password
);
1441 CFRelease(password
);
1443 /* update the PPP entity */
1444 CFDictionarySetValue(newOptions
, kSCEntNetPPP
, newEntity
);
1445 CFRelease(newEntity
);
1448 /* IPSec Shared Secret */
1449 if (sharedsecret
!= NULL
) {
1450 CFDictionaryRef entity
;
1451 CFMutableDictionaryRef newEntity
;
1453 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetIPSec
);
1454 if (isA_CFDictionary(entity
))
1455 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1457 newEntity
= CFDictionaryCreateMutable(NULL
,
1459 &kCFTypeDictionaryKeyCallBacks
,
1460 &kCFTypeDictionaryValueCallBacks
);
1462 /* set the IPSec Shared Secret */
1463 CFDictionarySetValue(newEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
1464 CFRelease(sharedsecret
);
1466 /* update the IPSec entity */
1467 CFDictionarySetValue(newOptions
, kSCEntNetIPSec
, newEntity
);
1468 CFRelease(newEntity
);
1471 /* update the userOptions dictionary */
1472 CFRelease(*userOptions
);
1473 *userOptions
= CFDictionaryCreateCopy(NULL
, newOptions
);
1474 CFRelease(newOptions
);
1479 //********************************************************************************
1480 // copyPasswordFromKeychain
1481 // --------------------------------------
1482 // Given a uniqueID, retrieve the password from the keychain
1483 //********************************************************************************
1485 copyPasswordFromKeychain(CFStringRef uniqueID
)
1487 CFArrayRef enumerator
;
1489 CFStringRef password
= NULL
;
1491 enumerator
= copyKeychainEnumerator(uniqueID
);
1492 if (enumerator
== NULL
) {
1493 return NULL
; // if no keychain enumerator
1496 n
= CFArrayGetCount(enumerator
);
1500 SecKeychainItemRef itemRef
;
1503 itemRef
= (SecKeychainItemRef
)CFArrayGetValueAtIndex(enumerator
, 0);
1504 result
= SecKeychainItemCopyContent(itemRef
, // itemRef
1508 (void *)&data
); // outData
1509 if ((result
== noErr
) && (data
!= NULL
) && (dataLen
> 0)) {
1510 password
= CFStringCreateWithBytes(NULL
, data
, dataLen
, kCFStringEncodingUTF8
, TRUE
);
1514 CFRelease(enumerator
);
1519 //********************************************************************************
1520 // copyKeychainEnumerator
1521 // --------------------------------------
1522 // Gather Keychain Enumerator
1523 //********************************************************************************
1525 copyKeychainEnumerator(CFStringRef uniqueIdentifier
)
1528 CFMutableArrayRef itemArray
= NULL
;
1530 SecKeychainSearchRef search
= NULL
;
1532 buf
= _SC_cfstring_to_cstring(uniqueIdentifier
, NULL
, 0, kCFStringEncodingUTF8
);
1534 // search for unique identifier in "svce" attribute
1535 SecKeychainAttribute attributes
[] = {{ kSecServiceItemAttr
,
1536 CFStringGetLength(uniqueIdentifier
),
1540 SecKeychainAttributeList attrList
= { sizeof(attributes
) / sizeof(*attributes
),
1543 result
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attrList
, &search
);
1544 if (result
== noErr
) {
1545 itemArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1547 while (result
== noErr
) {
1548 SecKeychainItemRef itemFound
= NULL
;
1550 result
= SecKeychainSearchCopyNext(search
, &itemFound
);
1551 if (result
!= noErr
) {
1556 CFArrayAppendValue(itemArray
, itemFound
);
1557 CFRelease(itemFound
);
1563 if (search
) CFRelease(search
);
1564 if (buf
) CFAllocatorDeallocate(NULL
, buf
);