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>
64 /* -------------------------------------------------------------------------------------------
65 ------------------------------------------------------------------------------------------- */
69 /* base CFType information */
73 CFStringRef serviceID
;
75 /* ref to PPP controller for control messages */
76 mach_port_t session_port
;
78 /* ref to PPP controller for notification messages */
79 CFMachPortRef notify_port
;
81 /* run loop source, callout, context, rl scheduling info */
82 CFRunLoopSourceRef rls
;
83 SCNetworkConnectionCallBack rlsFunction
;
84 SCNetworkConnectionContext rlsContext
;
85 CFMutableArrayRef rlList
;
90 } SCNetworkConnectionPrivate
, *SCNetworkConnectionPrivateRef
;
92 /* -------------------------------------------------------------------------------------------
93 ------------------------------------------------------------------------------------------- */
95 static __inline__ CFTypeRef
96 isA_SCNetworkConnection(CFTypeRef obj
)
98 return (isA_CFType(obj
, SCNetworkConnectionGetTypeID()));
101 /* -------------------------------------------------------------------------------------------
102 ------------------------------------------------------------------------------------------- */
105 __SCNetworkConnectionCopyDescription(CFTypeRef cf
)
107 CFAllocatorRef allocator
= CFGetAllocator(cf
);
108 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
109 CFMutableStringRef result
;
111 result
= CFStringCreateMutable(allocator
, 0);
112 CFStringAppendFormat(result
, NULL
, CFSTR("<SCNetworkConnection, %p [%p]> {\n"), cf
, allocator
);
113 CFStringAppendFormat(result
, NULL
, CFSTR(" serviceID = %@ \n"), connectionPrivate
->serviceID
);
114 CFStringAppendFormat(result
, NULL
, CFSTR("}"));
119 /* -------------------------------------------------------------------------------------------
120 ------------------------------------------------------------------------------------------- */
123 __SCNetworkConnectionDeallocate(CFTypeRef cf
)
125 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)cf
;
127 if (connectionPrivate
->debug
) {
128 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionDeallocate (0x%x)"), connectionPrivate
);
131 /* release resources */
132 if (connectionPrivate
->rlList
!= NULL
) {
133 CFRunLoopSourceInvalidate(connectionPrivate
->rls
);
134 CFRelease(connectionPrivate
->rls
);
135 CFRelease(connectionPrivate
->rlList
);
138 if (connectionPrivate
->notify_port
!= NULL
) {
139 CFMachPortInvalidate(connectionPrivate
->notify_port
);
140 CFRelease(connectionPrivate
->notify_port
);
143 if (connectionPrivate
->session_port
!= MACH_PORT_NULL
)
144 mach_port_destroy(mach_task_self(), connectionPrivate
->session_port
);
146 if (connectionPrivate
->rlsContext
.release
!= NULL
)
147 (*connectionPrivate
->rlsContext
.release
)(connectionPrivate
->rlsContext
.info
);
149 if (connectionPrivate
->serviceID
)
150 CFRelease(connectionPrivate
->serviceID
);
155 /* -------------------------------------------------------------------------------------------
156 ------------------------------------------------------------------------------------------- */
158 static pthread_once_t initialized
= PTHREAD_ONCE_INIT
;
160 static CFTypeID __kSCNetworkConnectionTypeID
= _kCFRuntimeNotATypeID
;
162 static const CFRuntimeClass __SCNetworkConnectionClass
= {
164 "SCNetworkConnection", // className
167 __SCNetworkConnectionDeallocate
, // dealloc
170 NULL
, // copyFormattingDesc
171 __SCNetworkConnectionCopyDescription
// copyDebugDesc
174 /* -------------------------------------------------------------------------------------------
175 ------------------------------------------------------------------------------------------- */
178 __SCNetworkConnectionInitialize(void)
180 __kSCNetworkConnectionTypeID
= _CFRuntimeRegisterClass(&__SCNetworkConnectionClass
);
184 /* -------------------------------------------------------------------------------------------
185 ------------------------------------------------------------------------------------------- */
187 static SCNetworkConnectionStatus
188 __SCNetworkConnectionConvertStatus (int state
)
190 SCNetworkConnectionStatus status
= kSCNetworkConnectionDisconnected
;
194 case PPP_CONNECTLINK
:
196 case PPP_AUTHENTICATE
:
200 status
= kSCNetworkConnectionConnecting
;
203 case PPP_DISCONNECTLINK
:
204 status
= kSCNetworkConnectionDisconnecting
;
208 status
= kSCNetworkConnectionConnected
;
214 status
= kSCNetworkConnectionDisconnected
;
219 /* -------------------------------------------------------------------------------------------
220 ------------------------------------------------------------------------------------------- */
223 __SCNetworkConnectionCallBack(CFMachPortRef port
, void * msg
, CFIndex size
, void * info
)
225 mach_msg_empty_rcv_t
* buf
= msg
;
226 SCNetworkConnectionRef connection
= (SCNetworkConnectionRef
)info
;
227 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
229 void (*context_release
)(const void *);
230 int error
= kSCStatusFailed
;
231 mach_msg_id_t msgid
= buf
->header
.msgh_id
;
232 int phase
= PPP_IDLE
;
233 SCNetworkConnectionCallBack rlsFunction
;
234 kern_return_t status
;
235 SCNetworkConnectionStatus scstatus
;
237 if (msgid
== MACH_NOTIFY_NO_SENDERS
) {
238 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("__SCNetworkConnectionCallBack: PPPController server died"));
240 status
= pppcontroller_getstatus(connectionPrivate
->session_port
, &phase
, &error
);
243 if (connectionPrivate
->rls
== NULL
) {
247 rlsFunction
= connectionPrivate
->rlsFunction
;
248 if (rlsFunction
== NULL
) {
252 if ((connectionPrivate
->rlsContext
.retain
!= NULL
) && (connectionPrivate
->rlsContext
.info
!= NULL
)) {
253 context_info
= (void *)(*connectionPrivate
->rlsContext
.retain
)(connectionPrivate
->rlsContext
.info
);
254 context_release
= connectionPrivate
->rlsContext
.release
;
256 context_info
= connectionPrivate
->rlsContext
.info
;
257 context_release
= NULL
;
260 scstatus
= __SCNetworkConnectionConvertStatus(phase
);
262 (*rlsFunction
)(connection
, scstatus
, context_info
);
263 if ((context_release
!= NULL
) && (context_info
!= NULL
)) {
264 (*context_release
)(context_info
);
270 /* -------------------------------------------------------------------------------------------
271 ------------------------------------------------------------------------------------------- */
272 static SCNetworkConnectionPrivateRef
273 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator
,
274 CFStringRef serviceID
,
275 SCNetworkConnectionCallBack callout
,
276 SCNetworkConnectionContext
*context
)
279 SCNetworkConnectionPrivateRef connectionPrivate
= NULL
;
282 CFDataRef dataRef
= NULL
;
284 int error
= kSCStatusFailed
;
285 CFMachPortContext mach_context
= {0, NULL
, NULL
, NULL
, NULL
};
286 mach_port_t notify_port
= MACH_PORT_NULL
;
287 mach_port_t port_old
;
290 kern_return_t status
;
291 mach_port_t unpriv_bootstrap_port
;
293 /* initialize runtime */
294 pthread_once(&initialized
, __SCNetworkConnectionInitialize
);
296 if ((bootstrap_status (bootstrap_port
, PPPCONTROLLER_SERVER
, &active
) != BOOTSTRAP_SUCCESS
) ||
297 (bootstrap_look_up(bootstrap_port
, PPPCONTROLLER_SERVER
, &server
) != BOOTSTRAP_SUCCESS
)) {
298 SCLog(_sc_verbose
, LOG_DEBUG
, CFSTR("PPP Controller server not found"));
302 /* allocate NetworkConnection */
303 size
= sizeof(SCNetworkConnectionPrivate
) - sizeof(CFRuntimeBase
);
304 connectionPrivate
= (SCNetworkConnectionPrivateRef
)_CFRuntimeCreateInstance(allocator
, __kSCNetworkConnectionTypeID
, size
, NULL
);
305 if (connectionPrivate
== NULL
) {
309 /* zero the data structure */
310 bzero(((u_char
*)connectionPrivate
)+sizeof(CFRuntimeBase
), size
);
312 /* save the serviceID */
313 connectionPrivate
->serviceID
= CFStringCreateCopy(NULL
, serviceID
);
315 /* get the debug environment variable */
316 envdebug
= getenv("PPPDebug");
318 if (sscanf(envdebug
, "%d", &connectionPrivate
->debug
) != 1)
319 connectionPrivate
->debug
= 1; /* PPPDebug value is invalid, set debug to 1 */
322 if (callout
!= NULL
) {
323 connectionPrivate
->rlsFunction
= callout
;
325 mach_context
.info
= (void*)connectionPrivate
;
326 connectionPrivate
->notify_port
= CFMachPortCreate(NULL
, __SCNetworkConnectionCallBack
, &mach_context
, NULL
);
327 if (connectionPrivate
->notify_port
== NULL
) {
331 notify_port
= CFMachPortGetPort(connectionPrivate
->notify_port
);
332 status
= mach_port_request_notification(mach_task_self(),
333 notify_port
, MACH_NOTIFY_NO_SENDERS
, 1,
334 notify_port
, MACH_MSG_TYPE_MAKE_SEND_ONCE
, &port_old
);
335 if (status
!= KERN_SUCCESS
) {
341 bcopy(context
, &connectionPrivate
->rlsContext
, sizeof(SCNetworkConnectionContext
));
342 if (context
->retain
!= NULL
) {
343 connectionPrivate
->rlsContext
.info
= (void *)(*context
->retain
)(context
->info
);
347 if (!_SCSerializeString(serviceID
, &dataRef
, &data
, &dataLen
)) {
351 status
= bootstrap_unprivileged(bootstrap_port
, &unpriv_bootstrap_port
);
352 if (status
!= BOOTSTRAP_SUCCESS
) {
356 status
= pppcontroller_attach(server
, data
, dataLen
, unpriv_bootstrap_port
, notify_port
,
357 &connectionPrivate
->session_port
, &error
);
359 mach_port_deallocate(mach_task_self(), unpriv_bootstrap_port
);
363 if (status
!= KERN_SUCCESS
) {
367 if (error
!= kSCStatusOK
) {
371 if (connectionPrivate
->debug
) {
372 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCreate (0x%x) succeeded for service ID: %@"), connectionPrivate
, serviceID
);
375 /* success, return the connection reference */
376 return connectionPrivate
;
381 /* failure, clean up and leave */
382 if (connectionPrivate
!= NULL
) {
383 if (connectionPrivate
->debug
)
384 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCreate (0x%x) failed for service ID: %@"), connectionPrivate
, serviceID
);
385 CFRelease(connectionPrivate
);
388 if (dataRef
) CFRelease(dataRef
);
393 /* -------------------------------------------------------------------------------------------
394 ------------------------------------------------------------------------------------------- */
397 SCNetworkConnectionGetTypeID(void) {
398 pthread_once(&initialized
, __SCNetworkConnectionInitialize
); /* initialize runtime */
399 return __kSCNetworkConnectionTypeID
;
402 /* -------------------------------------------------------------------------------------------
403 ------------------------------------------------------------------------------------------- */
405 SCNetworkConnectionRef
406 SCNetworkConnectionCreateWithServiceID(CFAllocatorRef allocator
,
407 CFStringRef serviceID
,
408 SCNetworkConnectionCallBack callout
,
409 SCNetworkConnectionContext
*context
)
411 SCNetworkConnectionPrivateRef connectionPrivate
;
413 if (!isA_CFString(serviceID
)) {
414 _SCErrorSet(kSCStatusInvalidArgument
);
418 connectionPrivate
= __SCNetworkConnectionCreatePrivate(allocator
, serviceID
, callout
, context
);
420 return (SCNetworkConnectionRef
)connectionPrivate
;
423 /* -------------------------------------------------------------------------------------------
424 ------------------------------------------------------------------------------------------- */
427 SCNetworkConnectionCopyServiceID(SCNetworkConnectionRef connection
)
429 if (!isA_SCNetworkConnection(connection
)) {
430 _SCErrorSet(kSCStatusInvalidArgument
);
434 return CFRetain(((SCNetworkConnectionPrivateRef
)connection
)->serviceID
);
437 /* -------------------------------------------------------------------------------------------
438 ------------------------------------------------------------------------------------------- */
441 SCNetworkConnectionCopyStatistics(SCNetworkConnectionRef connection
)
443 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
444 xmlDataOut_t data
= NULL
;
445 mach_msg_type_number_t datalen
;
446 int error
= kSCStatusFailed
;
447 CFPropertyListRef statistics
= NULL
;
448 kern_return_t status
;
450 if (!isA_SCNetworkConnection(connection
)) {
451 _SCErrorSet(kSCStatusInvalidArgument
);
455 status
= pppcontroller_copystatistics(connectionPrivate
->session_port
, &data
, &datalen
, &error
);
456 if (status
!= KERN_SUCCESS
) {
460 if (error
!= kSCStatusOK
) {
464 if ((data
== NULL
) ||
465 !_SCUnserialize(&statistics
, NULL
, data
, datalen
) ||
466 !isA_CFDictionary(statistics
)) {
474 if (statistics
) CFRelease(statistics
);
479 /* -------------------------------------------------------------------------------------------
480 ------------------------------------------------------------------------------------------- */
482 SCNetworkConnectionStatus
483 SCNetworkConnectionGetStatus(SCNetworkConnectionRef connection
)
485 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
486 int error
= kSCStatusFailed
;
488 SCNetworkConnectionStatus scstatus
;
489 kern_return_t status
;
491 if (!isA_SCNetworkConnection(connection
)) {
492 _SCErrorSet(kSCStatusInvalidArgument
);
493 return kSCNetworkConnectionInvalid
;
496 status
= pppcontroller_getstatus(connectionPrivate
->session_port
, &phase
, &error
);
497 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
498 return kSCNetworkConnectionDisconnected
;
501 scstatus
= __SCNetworkConnectionConvertStatus(phase
);
505 /* -------------------------------------------------------------------------------------------
506 ------------------------------------------------------------------------------------------- */
509 SCNetworkConnectionCopyExtendedStatus(SCNetworkConnectionRef connection
)
511 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
512 xmlDataOut_t data
= NULL
;
513 mach_msg_type_number_t datalen
;
514 int error
= kSCStatusFailed
;
515 CFPropertyListRef extstatus
= NULL
;
516 kern_return_t status
;
518 if (!isA_SCNetworkConnection(connection
)) {
519 _SCErrorSet(kSCStatusInvalidArgument
);
523 status
= pppcontroller_copyextendedstatus(connectionPrivate
->session_port
, &data
, &datalen
, &error
);
524 if (status
!= KERN_SUCCESS
) {
528 if (error
!= kSCStatusOK
) {
532 if ((data
== NULL
) ||
533 !_SCUnserialize(&extstatus
, NULL
, data
, datalen
) ||
534 !isA_CFDictionary(extstatus
)) {
542 if (extstatus
) CFRelease(extstatus
);
547 /* -------------------------------------------------------------------------------------------
548 ------------------------------------------------------------------------------------------- */
551 SCNetworkConnectionStart(SCNetworkConnectionRef connection
,
552 CFDictionaryRef userOptions
,
555 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
556 CFDataRef dataref
= NULL
;
559 int error
= kSCStatusFailed
;
560 kern_return_t status
;
562 if (!isA_SCNetworkConnection(connection
)) {
563 _SCErrorSet(kSCStatusInvalidArgument
);
567 if (connectionPrivate
->debug
) {
568 CFMutableDictionaryRef mdict
= NULL
, mdict1
;
569 CFDictionaryRef dict
;
571 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x)"), connectionPrivate
);
574 /* special code to remove secret information */
575 mdict
= CFDictionaryCreateMutableCopy(0, 0, userOptions
);
577 dict
= CFDictionaryGetValue(mdict
, kSCEntNetPPP
);
578 if (isA_CFDictionary(dict
)) {
579 mdict1
= CFDictionaryCreateMutableCopy(0, 0, dict
);
581 CFDictionaryReplaceValue(mdict1
, kSCPropNetPPPAuthPassword
, CFSTR("******"));
582 CFDictionarySetValue(mdict
, kSCEntNetPPP
, mdict1
);
587 dict
= CFDictionaryGetValue(mdict
, kSCEntNetL2TP
);
588 if (isA_CFDictionary(dict
)) {
589 mdict1
= CFDictionaryCreateMutableCopy(0, 0, dict
);
591 CFDictionaryReplaceValue(mdict1
, kSCPropNetL2TPIPSecSharedSecret
, CFSTR("******"));
592 CFDictionarySetValue(mdict
, kSCEntNetL2TP
, mdict1
);
597 dict
= CFDictionaryGetValue(mdict
, kSCEntNetIPSec
);
598 if (isA_CFDictionary(dict
)) {
599 mdict1
= CFDictionaryCreateMutableCopy(0, 0, dict
);
601 CFDictionaryReplaceValue(mdict1
, kSCPropNetIPSecSharedSecret
, CFSTR("******"));
602 CFDictionarySetValue(mdict
, kSCEntNetIPSec
, mdict1
);
609 SCLog(TRUE
, LOG_DEBUG
, CFSTR("User options: %@"), mdict
);
614 if (userOptions
&& !_SCSerialize(userOptions
, &dataref
, &data
, &datalen
)) {
618 status
= pppcontroller_start(connectionPrivate
->session_port
, data
, datalen
, linger
, &error
);
619 if (status
!= KERN_SUCCESS
) {
628 if (connectionPrivate
->debug
)
629 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStart (0x%x), return: %d"), connectionPrivate
, error
);
631 if (error
!= kSCStatusOK
) {
635 /* connection is now started */
640 if (dataref
) CFRelease(dataref
);
645 /* -------------------------------------------------------------------------------------------
646 ------------------------------------------------------------------------------------------- */
649 SCNetworkConnectionStop(SCNetworkConnectionRef connection
,
650 Boolean forceDisconnect
)
652 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
653 int error
= kSCStatusFailed
;
654 kern_return_t status
;
656 if (!isA_SCNetworkConnection(connection
)) {
657 _SCErrorSet(kSCStatusInvalidArgument
);
661 if (connectionPrivate
->debug
)
662 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x)"), connectionPrivate
);
664 status
= pppcontroller_stop(connectionPrivate
->session_port
, forceDisconnect
, &error
);
665 if (status
!= KERN_SUCCESS
) {
669 if (connectionPrivate
->debug
)
670 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionStop (0x%x), return: %d"), connectionPrivate
, error
);
672 if (error
!= kSCStatusOK
) {
676 /* connection is now disconnecting */
685 /* -------------------------------------------------------------------------------------------
686 ------------------------------------------------------------------------------------------- */
689 SCNetworkConnectionSuspend(SCNetworkConnectionRef connection
)
691 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
692 int error
= kSCStatusFailed
;
693 kern_return_t status
;
695 if (!isA_SCNetworkConnection(connection
)) {
696 _SCErrorSet(kSCStatusInvalidArgument
);
700 if (connectionPrivate
->debug
)
701 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x)"), connectionPrivate
);
703 status
= pppcontroller_suspend(connectionPrivate
->session_port
, &error
);
704 if (status
!= KERN_SUCCESS
) {
708 if (connectionPrivate
->debug
)
709 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionSuspend (0x%x), return: %d"), connectionPrivate
, error
);
711 if (error
!= kSCStatusOK
) {
715 /* connection is now suspended */
724 /* -------------------------------------------------------------------------------------------
725 ------------------------------------------------------------------------------------------- */
728 SCNetworkConnectionResume(SCNetworkConnectionRef connection
)
730 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
731 int error
= kSCStatusFailed
;
732 kern_return_t status
;
734 if (!isA_SCNetworkConnection(connection
)) {
735 _SCErrorSet(kSCStatusInvalidArgument
);
739 if (connectionPrivate
->debug
)
740 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x)"), connectionPrivate
);
742 status
= pppcontroller_resume(connectionPrivate
->session_port
, &error
);
743 if (status
!= KERN_SUCCESS
) {
747 if (connectionPrivate
->debug
)
748 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionResume (0x%x), return: %d"), connectionPrivate
, error
);
750 if (error
!= kSCStatusOK
) {
754 /* connection is now resume */
763 /* -------------------------------------------------------------------------------------------
764 ------------------------------------------------------------------------------------------- */
767 SCNetworkConnectionCopyUserOptions(SCNetworkConnectionRef connection
)
769 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
770 xmlDataOut_t data
= NULL
;
771 mach_msg_type_number_t datalen
;
772 int error
= kSCStatusFailed
;
773 kern_return_t status
;
774 CFPropertyListRef userOptions
= NULL
;
776 if (!isA_SCNetworkConnection(connection
)) {
777 _SCErrorSet(kSCStatusInvalidArgument
);
781 status
= pppcontroller_copyuseroptions(connectionPrivate
->session_port
, &data
, &datalen
, &error
);
782 if (status
!= KERN_SUCCESS
) {
786 if (error
!= kSCStatusOK
) {
790 // no data were used, return an empty dictionary
792 CFDictionaryRef dict
;
794 dict
= CFDictionaryCreateMutable(NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
796 _SCErrorSet(kSCStatusFailed
); // XXX
801 if (!_SCUnserialize(&userOptions
, NULL
, data
, datalen
) ||
802 !isA_CFDictionary(userOptions
)) {
810 if (userOptions
) CFRelease(userOptions
);
815 /* -------------------------------------------------------------------------------------------
816 ------------------------------------------------------------------------------------------- */
819 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection
,
820 CFRunLoopRef runLoop
,
821 CFStringRef runLoopMode
)
823 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
824 int error
= kSCStatusFailed
;
825 kern_return_t status
;
827 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
828 _SCErrorSet(kSCStatusInvalidArgument
);
832 if (connectionPrivate
->rlsFunction
== NULL
) {
833 _SCErrorSet(kSCStatusInvalidArgument
);
837 if ((connectionPrivate
->rlList
!= NULL
) &&
838 _SC_isScheduled(NULL
, runLoop
, runLoopMode
, connectionPrivate
->rlList
)) {
839 /* already scheduled */
840 _SCErrorSet(kSCStatusFailed
);
844 if (connectionPrivate
->rlList
== NULL
) {
845 status
= pppcontroller_notification(connectionPrivate
->session_port
, 1, &error
);
846 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
851 connectionPrivate
->rls
= CFMachPortCreateRunLoopSource(NULL
, connectionPrivate
->notify_port
, 0);
852 connectionPrivate
->rlList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
855 CFRunLoopAddSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
856 _SC_schedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
);
861 /* -------------------------------------------------------------------------------------------
862 ------------------------------------------------------------------------------------------- */
865 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection
,
866 CFRunLoopRef runLoop
,
867 CFStringRef runLoopMode
)
869 SCNetworkConnectionPrivateRef connectionPrivate
= (SCNetworkConnectionPrivateRef
)connection
;
870 int error
= kSCStatusFailed
;
871 kern_return_t status
;
873 if (!isA_SCNetworkConnection(connection
) || runLoop
== NULL
|| runLoopMode
== NULL
) {
874 _SCErrorSet(kSCStatusInvalidArgument
);
878 if ((connectionPrivate
->rlList
== NULL
) ||
879 !_SC_unschedule(connectionPrivate
, runLoop
, runLoopMode
, connectionPrivate
->rlList
, FALSE
)) {
880 /* if not currently scheduled */
881 _SCErrorSet(kSCStatusFailed
);
885 CFRunLoopRemoveSource(runLoop
, connectionPrivate
->rls
, runLoopMode
);
887 if (CFArrayGetCount(connectionPrivate
->rlList
) == 0) {
888 CFRelease(connectionPrivate
->rls
);
889 connectionPrivate
->rls
= NULL
;
890 CFRelease(connectionPrivate
->rlList
);
891 connectionPrivate
->rlList
= NULL
;
893 status
= pppcontroller_notification(connectionPrivate
->session_port
, 0, &error
);
894 if ((status
!= KERN_SUCCESS
) || (error
!= kSCStatusOK
)) {
904 //************************* USER LEVEL DIAL API **********************************
907 #define k_NetworkConnect_Notification "com.apple.networkConnect"
908 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
909 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
911 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
912 #define k_Last_Service_Id_Key CFSTR("ServiceID")
913 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
916 /* Private Prototypes */
917 static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
918 static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session
, CFStringRef
*serviceID
);
919 static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
);
920 static Boolean
SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
);
921 static void addPasswordFromKeychain (SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
);
922 static CFStringRef
copyPasswordFromKeychain (CFStringRef uniqueID
);
923 static CFArrayRef
copyKeychainEnumerator (CFStringRef uniqueIdentifier
);
925 static int notify_userprefs_token
= -1;
928 * return TRUE if domain1 ends with domain2, and will check for trailing "."
931 domainEndsWithDomain(CFStringRef domain1
, CFStringRef domain2
)
935 CFStringRef s1
= NULL
;
936 Boolean s1_created
= FALSE
;
937 CFStringRef s2
= NULL
;
938 Boolean s2_created
= FALSE
;
940 if (CFStringHasSuffix(domain1
, CFSTR("."))) {
942 range
.length
= CFStringGetLength(domain1
) - 1;
943 s1
= CFStringCreateWithSubstring(NULL
, domain1
, range
);
952 if (CFStringHasSuffix(domain2
, CFSTR("."))) {
954 range
.length
= CFStringGetLength(domain2
) - 1;
955 s2
= CFStringCreateWithSubstring(NULL
, domain2
, range
);
964 ret
= CFStringHasSuffix(s1
, s2
);
968 if (s1_created
) CFRelease(s1
);
969 if (s2_created
) CFRelease(s2
);
975 SCNetworkConnectionCopyUserPreferences(CFDictionaryRef selectionOptions
,
976 CFStringRef
*serviceID
,
977 CFDictionaryRef
*userOptions
)
982 SCDynamicStoreRef session
;
983 Boolean success
= FALSE
;
986 envdebug
= getenv("PPPDebug");
988 if (sscanf(envdebug
, "%d", &debug
) != 1)
989 debug
= 1; /* PPPDebug value is invalid, set debug to 1 */
992 if (notify_userprefs_token
== -1) {
993 status
= notify_register_check(k_NetworkConnect_Notification
, ¬ify_userprefs_token
);
994 if (status
!= NOTIFY_STATUS_OK
)
995 notify_userprefs_token
= -1;
998 notify_check(notify_userprefs_token
, &prefsChanged
);
1002 if (notify_userprefs_token
!= -1)
1003 notify_check(notify_userprefs_token
, &prefsChanged
);
1006 // NOTE: we are currently ignoring selectionOptions
1009 *userOptions
= NULL
;
1011 session
= SCDynamicStoreCreate(NULL
, CFSTR("SCNetworkConnection"), NULL
, NULL
);
1012 if (session
== NULL
) {
1013 fprintf(stderr
, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
1017 if (selectionOptions
) {
1018 Boolean catchAllFound
= FALSE
;
1019 CFIndex catchAllService
= 0;
1020 CFIndex catchAllConfig
= 0;
1021 CFStringRef hostName
= NULL
;
1022 CFStringRef priority
= NULL
;
1023 CFArrayRef serviceNames
= NULL
;
1024 CFDictionaryRef services
= NULL
;
1025 CFIndex serviceIndex
;
1026 CFIndex servicesCount
;
1028 hostName
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandHostName
);
1029 if (!isA_CFString(hostName
))
1032 // can't select anything
1033 if (hostName
== NULL
)
1034 goto done_selection
;
1036 priority
= CFDictionaryGetValue(selectionOptions
, kSCPropNetPPPOnDemandPriority
);
1037 if (!isA_CFString(priority
))
1038 priority
= kSCValNetPPPOnDemandPriorityDefault
;
1041 if (!isA_CFArray(serviceNames
))
1042 goto done_selection
;
1045 if (!isA_CFDictionary(services
))
1046 goto done_selection
;
1048 servicesCount
= CFArrayGetCount(serviceNames
);
1049 for (serviceIndex
= 0; serviceIndex
< servicesCount
; serviceIndex
++) {
1050 CFIndex configIndex
;
1051 CFIndex configsCount
;
1052 CFArrayRef serviceConfigs
;
1053 CFStringRef serviceName
;
1056 serviceName
= CFArrayGetValueAtIndex(serviceNames
, serviceIndex
);
1057 if (!isA_CFString(serviceName
))
1060 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1061 if (!isA_CFArray(serviceConfigs
))
1064 configsCount
= CFArrayGetCount(serviceConfigs
);
1065 for (configIndex
= 0; configIndex
< configsCount
; configIndex
++) {
1066 CFNumberRef autodial
;
1067 CFDictionaryRef config
;
1068 CFDictionaryRef pppConfig
;
1070 config
= CFArrayGetValueAtIndex(serviceConfigs
, configIndex
);
1071 if (!isA_CFDictionary(config
))
1074 pppConfig
= CFDictionaryGetValue(config
, kSCEntNetPPP
);
1075 if (!isA_CFDictionary(pppConfig
))
1078 autodial
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandEnabled
);
1079 if (!isA_CFNumber(autodial
))
1082 CFNumberGetValue(autodial
, kCFNumberIntType
, &val
);
1084 CFArrayRef autoDomains
;
1085 CFIndex domainIndex
;
1086 CFIndex domainsCount
;
1088 /* we found an conditional connection enabled configuration */
1091 autoDomains
= CFDictionaryGetValue(pppConfig
, kSCPropNetPPPOnDemandDomains
);
1092 if (!isA_CFArray(autoDomains
))
1095 domainsCount
= CFArrayGetCount(autoDomains
);
1096 for (domainIndex
= 0; domainIndex
< domainsCount
; domainIndex
++) {
1099 domain
= CFArrayGetValueAtIndex(autoDomains
, domainIndex
);
1100 if (!isA_CFString(domain
))
1103 if (!catchAllFound
&&
1104 (CFStringCompare(domain
, CFSTR(""), 0) == kCFCompareEqualTo
1105 || CFStringCompare(domain
, CFSTR("."), 0) == kCFCompareEqualTo
)) {
1106 // found a catch all
1107 catchAllFound
= TRUE
;
1108 catchAllService
= serviceIndex
;
1109 catchAllConfig
= configIndex
;
1112 if (domainEndsWithDomain(hostName
, domain
)) {
1113 // found matching configuration
1114 *serviceID
= serviceName
;
1115 CFRetain(*serviceID
);
1116 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1117 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandHostName
, hostName
);
1118 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1119 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1121 goto done_selection
;
1128 // config not found, do we have a catchall ?
1129 if (catchAllFound
) {
1130 CFDictionaryRef config
;
1131 CFArrayRef serviceConfigs
;
1132 CFStringRef serviceName
;
1134 serviceName
= CFArrayGetValueAtIndex(serviceNames
, catchAllService
);
1135 serviceConfigs
= CFDictionaryGetValue(services
, serviceName
);
1136 config
= CFArrayGetValueAtIndex(serviceConfigs
, catchAllConfig
);
1138 *serviceID
= serviceName
;
1139 CFRetain(*serviceID
);
1140 *userOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, config
);
1141 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandHostName
, hostName
);
1142 CFDictionarySetValue((CFMutableDictionaryRef
)*userOptions
, kSCPropNetPPPOnDemandPriority
, priority
);
1143 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1145 goto done_selection
;
1151 CFRelease(serviceNames
);
1153 CFRelease(services
);
1157 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@"), success
? CFSTR("succeeded") : CFSTR("failed"));
1158 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Selection options: %@"), selectionOptions
);
1164 /* we don't have selection options */
1166 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
1167 success
= SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session
, serviceID
);
1169 if (success
&& (*serviceID
!= NULL
)) {
1170 // (2) Get the list of user data for this service ID
1171 CFPropertyListRef userServices
= NULL
;
1174 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
1175 if (userServices
!= NULL
) {
1176 if (isA_CFArray(userServices
)) {
1177 // (4) Get the default set of user options for this service
1178 success
= SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray((CFArrayRef
)userServices
,
1180 if(success
&& (userOptions
!= NULL
)) {
1181 addPasswordFromKeychain(session
, *serviceID
, userOptions
);
1184 fprintf(stderr
, "Error, userServices are not of type CFArray!\n");
1187 CFRelease(userServices
); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
1192 SCLog(TRUE
, LOG_DEBUG
, CFSTR("SCNetworkConnectionCopyUserPreferences %@, no selection options"), success
? CFSTR("succeeded") : CFSTR("failed"));
1200 //*******************************************************************************************
1201 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
1202 // ----------------------------------------------------
1203 // Try to find the service id to connect
1204 // (1) Start by looking at the last service used in Internet Connect
1205 // (2) If Internet Connect has not been used, find the PPP service with the highest ordering
1206 //********************************************************************************************
1208 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1210 Boolean foundService
= FALSE
;
1211 CFPropertyListRef lastServiceSelectedInIC
= NULL
;
1214 // we found the service the user last had open in IC
1215 if (lastServiceSelectedInIC
!= NULL
) {
1216 // make sure its a PPP service
1217 if (SCNetworkConnectionPrivateIsPPPService(session
, lastServiceSelectedInIC
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1218 // make sure the service that we found is valid
1219 CFDictionaryRef dict
;
1222 key
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1223 kSCDynamicStoreDomainSetup
,
1224 lastServiceSelectedInIC
,
1225 kSCEntNetInterface
);
1226 dict
= SCDynamicStoreCopyValue(session
, key
);
1230 *serviceID
= CFRetain(lastServiceSelectedInIC
);
1231 foundService
= TRUE
;
1234 CFRelease(lastServiceSelectedInIC
);
1237 if (!foundService
) {
1238 foundService
= SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session
, serviceID
);
1241 return foundService
;
1244 //********************************************************************************
1245 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
1246 // -------------------------------------------------------
1247 // Find the highest ordered PPP service in the dynamic store
1248 //********************************************************************************
1250 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session
, CFStringRef
*serviceID
)
1252 CFDictionaryRef dict
= NULL
;
1253 CFStringRef key
= NULL
;
1254 CFArrayRef serviceIDs
= NULL
;
1255 Boolean success
= FALSE
;
1263 key
= SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL
, kSCDynamicStoreDomainSetup
, kSCEntNetIPv4
);
1265 fprintf(stderr
, "Error, Setup Key == NULL!\n");
1269 dict
= SCDynamicStoreCopyValue(session
, key
);
1270 if (!isA_CFDictionary(dict
)) {
1271 fprintf(stderr
, "no global IPv4 entity\n");
1275 serviceIDs
= CFDictionaryGetValue(dict
, kSCPropNetServiceOrder
); // array of service id's
1276 if (!isA_CFArray(serviceIDs
)) {
1277 fprintf(stderr
, "service order not specified\n");
1281 count
= CFArrayGetCount(serviceIDs
);
1282 for (i
= 0; i
< count
; i
++) {
1283 CFStringRef service
= CFArrayGetValueAtIndex(serviceIDs
, i
);
1285 if (SCNetworkConnectionPrivateIsPPPService(session
, service
, kSCValNetInterfaceSubTypePPPSerial
, kSCValNetInterfaceSubTypePPPoE
)) {
1286 *serviceID
= CFRetain(service
);
1293 if (key
!= NULL
) CFRelease(key
);
1294 if (dict
!= NULL
) CFRelease(dict
);
1299 //********************************************************************************
1300 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
1301 // ---------------------------------------------------------
1302 // Copy over user preferences for a particular service if they exist
1303 //********************************************************************************
1305 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray
, CFDictionaryRef
*userOptions
)
1307 CFIndex count
= CFArrayGetCount(userOptionsArray
);
1310 for (i
= 0; i
< count
; i
++) {
1311 // (1) Find the dictionary
1312 CFPropertyListRef propertyList
= CFArrayGetValueAtIndex(userOptionsArray
, i
);
1314 if (isA_CFDictionary(propertyList
) != NULL
) {
1315 // See if there's a value for dial on demand
1316 CFPropertyListRef value
;
1318 value
= CFDictionaryGetValue((CFDictionaryRef
)propertyList
, k_Dial_Default_Key
);
1319 if (isA_CFBoolean(value
) != NULL
) {
1320 if (CFBooleanGetValue(value
)) {
1321 // we found the default user options
1322 *userOptions
= CFDictionaryCreateCopy(NULL
,
1323 (CFDictionaryRef
)propertyList
);
1333 //********************************************************************************
1334 // SCNetworkConnectionPrivateIsServiceType
1335 // --------------------------------------
1336 // Check and see if the service is a PPP service of the given types
1337 //********************************************************************************
1339 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session
, CFStringRef serviceID
, CFStringRef subType1
, CFStringRef subType2
)
1341 CFStringRef entityKey
;
1342 Boolean isPPPService
= FALSE
;
1343 Boolean isMatchingSubType
= FALSE
;
1344 CFDictionaryRef serviceDict
;
1346 entityKey
= SCDynamicStoreKeyCreateNetworkServiceEntity(NULL
,
1347 kSCDynamicStoreDomainSetup
,
1349 kSCEntNetInterface
);
1350 if (entityKey
== NULL
) {
1354 serviceDict
= SCDynamicStoreCopyValue(session
, entityKey
);
1355 if (serviceDict
!= NULL
) {
1356 if (isA_CFDictionary(serviceDict
)) {
1358 CFStringRef subtype
;
1360 type
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceType
);
1361 if (isA_CFString(type
)) {
1362 isPPPService
= CFEqual(type
, kSCValNetInterfaceTypePPP
);
1365 subtype
= CFDictionaryGetValue(serviceDict
, kSCPropNetInterfaceSubType
);
1366 if (isA_CFString(subtype
)) {
1367 isMatchingSubType
= CFEqual(subtype
, subType1
);
1368 if (!isMatchingSubType
&& subType2
)
1369 isMatchingSubType
= CFEqual(subtype
, subType2
);
1372 CFRelease(serviceDict
);
1374 CFRelease(entityKey
);
1376 return (isPPPService
&& isMatchingSubType
);
1379 //********************************************************************************
1380 // addPasswordFromKeychain
1381 // --------------------------------------
1382 // Get the password and shared secret out of the keychain and add
1383 // them to the PPP and IPSec dictionaries
1384 //********************************************************************************
1386 addPasswordFromKeychain(SCDynamicStoreRef session
, CFStringRef serviceID
, CFDictionaryRef
*userOptions
)
1388 CFPropertyListRef uniqueID
;
1389 CFStringRef password
;
1390 CFStringRef sharedsecret
= NULL
;
1392 /* user options must exist */
1393 if (*userOptions
== NULL
)
1396 /* first, get the unique identifier used to store passwords in the keychain */
1397 uniqueID
= CFDictionaryGetValue(*userOptions
, k_Unique_Id_Key
);
1398 if (!isA_CFString(uniqueID
))
1401 /* first, get the PPP password */
1402 password
= copyPasswordFromKeychain(uniqueID
);
1404 /* then, if necessary, get the IPSec Shared Secret */
1405 if (SCNetworkConnectionPrivateIsPPPService(session
, serviceID
, kSCValNetInterfaceSubTypeL2TP
, 0)) {
1406 CFMutableStringRef uniqueIDSS
;
1408 uniqueIDSS
= CFStringCreateMutableCopy(NULL
, 0, uniqueID
);
1409 CFStringAppend(uniqueIDSS
, CFSTR(".SS"));
1410 sharedsecret
= copyPasswordFromKeychain(uniqueIDSS
);
1411 CFRelease(uniqueIDSS
);
1414 /* did we find our information in the key chain ? */
1415 if ((password
!= NULL
) || (sharedsecret
!= NULL
)) {
1416 CFMutableDictionaryRef newOptions
;
1418 newOptions
= CFDictionaryCreateMutableCopy(NULL
, 0, *userOptions
);
1421 if (password
!= NULL
) {
1422 CFDictionaryRef entity
;
1423 CFMutableDictionaryRef newEntity
;
1425 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetPPP
);
1426 if (isA_CFDictionary(entity
))
1427 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1429 newEntity
= CFDictionaryCreateMutable(NULL
,
1431 &kCFTypeDictionaryKeyCallBacks
,
1432 &kCFTypeDictionaryValueCallBacks
);
1435 /* set the PPP password */
1436 CFDictionarySetValue(newEntity
, kSCPropNetPPPAuthPassword
, password
);
1437 CFRelease(password
);
1439 /* update the PPP entity */
1440 CFDictionarySetValue(newOptions
, kSCEntNetPPP
, newEntity
);
1441 CFRelease(newEntity
);
1444 /* IPSec Shared Secret */
1445 if (sharedsecret
!= NULL
) {
1446 CFDictionaryRef entity
;
1447 CFMutableDictionaryRef newEntity
;
1449 entity
= CFDictionaryGetValue(*userOptions
, kSCEntNetIPSec
);
1450 if (isA_CFDictionary(entity
))
1451 newEntity
= CFDictionaryCreateMutableCopy(NULL
, 0, entity
);
1453 newEntity
= CFDictionaryCreateMutable(NULL
,
1455 &kCFTypeDictionaryKeyCallBacks
,
1456 &kCFTypeDictionaryValueCallBacks
);
1458 /* set the IPSec Shared Secret */
1459 CFDictionarySetValue(newEntity
, kSCPropNetIPSecSharedSecret
, sharedsecret
);
1460 CFRelease(sharedsecret
);
1462 /* update the IPSec entity */
1463 CFDictionarySetValue(newOptions
, kSCEntNetIPSec
, newEntity
);
1464 CFRelease(newEntity
);
1467 /* update the userOptions dictionary */
1468 CFRelease(*userOptions
);
1469 *userOptions
= CFDictionaryCreateCopy(NULL
, newOptions
);
1470 CFRelease(newOptions
);
1475 //********************************************************************************
1476 // copyPasswordFromKeychain
1477 // --------------------------------------
1478 // Given a uniqueID, retrieve the password from the keychain
1479 //********************************************************************************
1481 copyPasswordFromKeychain(CFStringRef uniqueID
)
1483 CFArrayRef enumerator
;
1485 CFStringRef password
= NULL
;
1487 enumerator
= copyKeychainEnumerator(uniqueID
);
1488 if (enumerator
== NULL
) {
1489 return NULL
; // if no keychain enumerator
1492 n
= CFArrayGetCount(enumerator
);
1496 SecKeychainItemRef itemRef
;
1499 itemRef
= (SecKeychainItemRef
)CFArrayGetValueAtIndex(enumerator
, 0);
1500 result
= SecKeychainItemCopyContent(itemRef
, // itemRef
1504 (void *)&data
); // outData
1505 if ((result
== noErr
) && (data
!= NULL
) && (dataLen
> 0)) {
1506 password
= CFStringCreateWithBytes(NULL
, data
, dataLen
, kCFStringEncodingUTF8
, TRUE
);
1510 CFRelease(enumerator
);
1515 //********************************************************************************
1516 // copyKeychainEnumerator
1517 // --------------------------------------
1518 // Gather Keychain Enumerator
1519 //********************************************************************************
1521 copyKeychainEnumerator(CFStringRef uniqueIdentifier
)
1524 CFMutableArrayRef itemArray
= NULL
;
1526 SecKeychainSearchRef search
= NULL
;
1528 buf
= _SC_cfstring_to_cstring(uniqueIdentifier
, NULL
, 0, kCFStringEncodingUTF8
);
1530 // search for unique identifier in "svce" attribute
1531 SecKeychainAttribute attributes
[] = {{ kSecServiceItemAttr
,
1532 CFStringGetLength(uniqueIdentifier
),
1536 SecKeychainAttributeList attrList
= { sizeof(attributes
) / sizeof(*attributes
),
1539 result
= SecKeychainSearchCreateFromAttributes(NULL
, kSecGenericPasswordItemClass
, &attrList
, &search
);
1540 if (result
== noErr
) {
1541 itemArray
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
1543 while (result
== noErr
) {
1544 SecKeychainItemRef itemFound
= NULL
;
1546 result
= SecKeychainSearchCopyNext(search
, &itemFound
);
1547 if (result
!= noErr
) {
1552 CFArrayAppendValue(itemArray
, itemFound
);
1553 CFRelease(itemFound
);
1559 if (search
) CFRelease(search
);
1560 if (buf
) CFAllocatorDeallocate(NULL
, buf
);