]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConnection.c
eb67e80272a943a953e286cf2857f6523432d6c5
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConnection.c
1 /*
2 * Copyright (c) 2003-2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * April 14, 2004 Christophe Allie <callie@apple.com>
28 * - use mach messages
29
30 * December 20, 2002 Christophe Allie <callie@apple.com>
31 * - initial revision
32 */
33
34 /* -------------------------------------------------------------------------------------------
35 ------------------------------------------------------------------------------------------- */
36
37 #include <CoreFoundation/CoreFoundation.h>
38 #include <CoreFoundation/CFRuntime.h>
39
40 #include <Security/Security.h>
41 #include "dy_framework.h"
42
43 #include <SystemConfiguration/SystemConfiguration.h>
44 #include <SystemConfiguration/SCPrivate.h>
45 #include <SystemConfiguration/SCValidation.h>
46
47 #include <servers/bootstrap.h>
48
49 #include <pthread.h>
50 #include <notify.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #include <unistd.h>
55 #include <sys/ioctl.h>
56 #include <sys/socket.h>
57 #include <net/if.h>
58
59 #include <ppp/ppp_msg.h>
60 #include <ppp/PPPControllerPriv.h>
61 #include "pppcontroller.h"
62 #include <ppp/pppcontroller_types.h>
63
64 /* -------------------------------------------------------------------------------------------
65 ------------------------------------------------------------------------------------------- */
66
67 typedef struct {
68
69 /* base CFType information */
70 CFRuntimeBase cfBase;
71
72 /* service ID */
73 CFStringRef serviceID;
74
75 /* ref to PPP controller for control messages */
76 mach_port_t session_port;
77
78 /* ref to PPP controller for notification messages */
79 CFMachPortRef notify_port;
80
81 /* run loop source, callout, context, rl scheduling info */
82 CFRunLoopSourceRef rls;
83 SCNetworkConnectionCallBack rlsFunction;
84 SCNetworkConnectionContext rlsContext;
85 CFMutableArrayRef rlList;
86
87 /* misc info */
88 int debug;
89
90 } SCNetworkConnectionPrivate, *SCNetworkConnectionPrivateRef;
91
92 /* -------------------------------------------------------------------------------------------
93 ------------------------------------------------------------------------------------------- */
94
95 static __inline__ CFTypeRef
96 isA_SCNetworkConnection(CFTypeRef obj)
97 {
98 return (isA_CFType(obj, SCNetworkConnectionGetTypeID()));
99 }
100
101 /* -------------------------------------------------------------------------------------------
102 ------------------------------------------------------------------------------------------- */
103
104 static CFStringRef
105 __SCNetworkConnectionCopyDescription(CFTypeRef cf)
106 {
107 CFAllocatorRef allocator = CFGetAllocator(cf);
108 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)cf;
109 CFMutableStringRef result;
110
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("}"));
115
116 return result;
117 }
118
119 /* -------------------------------------------------------------------------------------------
120 ------------------------------------------------------------------------------------------- */
121
122 static void
123 __SCNetworkConnectionDeallocate(CFTypeRef cf)
124 {
125 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)cf;
126
127 if (connectionPrivate->debug) {
128 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionDeallocate (0x%x)"), connectionPrivate);
129 }
130
131 /* release resources */
132 if (connectionPrivate->rlList != NULL) {
133 CFRunLoopSourceInvalidate(connectionPrivate->rls);
134 CFRelease(connectionPrivate->rls);
135 CFRelease(connectionPrivate->rlList);
136 }
137
138 if (connectionPrivate->notify_port != NULL) {
139 CFMachPortInvalidate(connectionPrivate->notify_port);
140 CFRelease(connectionPrivate->notify_port);
141 }
142
143 if (connectionPrivate->session_port != MACH_PORT_NULL)
144 mach_port_destroy(mach_task_self(), connectionPrivate->session_port);
145
146 if (connectionPrivate->rlsContext.release != NULL)
147 (*connectionPrivate->rlsContext.release)(connectionPrivate->rlsContext.info);
148
149 if (connectionPrivate->serviceID)
150 CFRelease(connectionPrivate->serviceID);
151
152 return;
153 }
154
155 /* -------------------------------------------------------------------------------------------
156 ------------------------------------------------------------------------------------------- */
157
158 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
159
160 static CFTypeID __kSCNetworkConnectionTypeID = _kCFRuntimeNotATypeID;
161
162 static const CFRuntimeClass __SCNetworkConnectionClass = {
163 0, // version
164 "SCNetworkConnection", // className
165 NULL, // init
166 NULL, // copy
167 __SCNetworkConnectionDeallocate, // dealloc
168 NULL, // equal
169 NULL, // hash
170 NULL, // copyFormattingDesc
171 __SCNetworkConnectionCopyDescription // copyDebugDesc
172 };
173
174 /* -------------------------------------------------------------------------------------------
175 ------------------------------------------------------------------------------------------- */
176
177 static void
178 __SCNetworkConnectionInitialize(void)
179 {
180 __kSCNetworkConnectionTypeID = _CFRuntimeRegisterClass(&__SCNetworkConnectionClass);
181 return;
182 }
183
184 /* -------------------------------------------------------------------------------------------
185 ------------------------------------------------------------------------------------------- */
186
187 static SCNetworkConnectionStatus
188 __SCNetworkConnectionConvertStatus (int state)
189 {
190 SCNetworkConnectionStatus status = kSCNetworkConnectionDisconnected;
191
192 switch (state) {
193 case PPP_INITIALIZE:
194 case PPP_CONNECTLINK:
195 case PPP_ESTABLISH:
196 case PPP_AUTHENTICATE:
197 case PPP_CALLBACK:
198 case PPP_NETWORK:
199 case PPP_WAITONBUSY:
200 status = kSCNetworkConnectionConnecting;
201 break;
202 case PPP_TERMINATE:
203 case PPP_DISCONNECTLINK:
204 status = kSCNetworkConnectionDisconnecting;
205 break;
206 case PPP_RUNNING:
207 case PPP_ONHOLD:
208 status = kSCNetworkConnectionConnected;
209 break;
210 case PPP_IDLE:
211 case PPP_DORMANT:
212 case PPP_HOLDOFF:
213 default:
214 status = kSCNetworkConnectionDisconnected;
215 }
216 return status;
217 }
218
219 /* -------------------------------------------------------------------------------------------
220 ------------------------------------------------------------------------------------------- */
221
222 static void
223 __SCNetworkConnectionCallBack(CFMachPortRef port, void * msg, CFIndex size, void * info)
224 {
225 mach_msg_empty_rcv_t * buf = msg;
226 SCNetworkConnectionRef connection = (SCNetworkConnectionRef)info;
227 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
228 void *context_info;
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;
236
237 if (msgid == MACH_NOTIFY_NO_SENDERS) {
238 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkConnectionCallBack: PPPController server died"));
239 } else {
240 status = pppcontroller_getstatus(connectionPrivate->session_port, &phase, &error);
241 }
242
243 if (connectionPrivate->rls == NULL) {
244 return;
245 }
246
247 rlsFunction = connectionPrivate->rlsFunction;
248 if (rlsFunction == NULL) {
249 return;
250 }
251
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;
255 } else {
256 context_info = connectionPrivate->rlsContext.info;
257 context_release = NULL;
258 }
259
260 scstatus = __SCNetworkConnectionConvertStatus(phase);
261
262 (*rlsFunction)(connection, scstatus, context_info);
263 if ((context_release != NULL) && (context_info != NULL)) {
264 (*context_release)(context_info);
265 }
266
267 return;
268 }
269
270 /* -------------------------------------------------------------------------------------------
271 ------------------------------------------------------------------------------------------- */
272 static SCNetworkConnectionPrivateRef
273 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator,
274 CFStringRef serviceID,
275 SCNetworkConnectionCallBack callout,
276 SCNetworkConnectionContext *context)
277 {
278 boolean_t active;
279 SCNetworkConnectionPrivateRef connectionPrivate = NULL;
280 void *data;
281 CFIndex dataLen;
282 CFDataRef dataRef = NULL;
283 char *envdebug;
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;
288 mach_port_t server;
289 uint32_t size;
290 kern_return_t status;
291 mach_port_t unpriv_bootstrap_port;
292
293 /* initialize runtime */
294 pthread_once(&initialized, __SCNetworkConnectionInitialize);
295
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"));
299 goto fail;
300 }
301
302 /* allocate NetworkConnection */
303 size = sizeof(SCNetworkConnectionPrivate) - sizeof(CFRuntimeBase);
304 connectionPrivate = (SCNetworkConnectionPrivateRef)_CFRuntimeCreateInstance(allocator, __kSCNetworkConnectionTypeID, size, NULL);
305 if (connectionPrivate == NULL) {
306 goto fail;
307 }
308
309 /* zero the data structure */
310 bzero(((u_char*)connectionPrivate)+sizeof(CFRuntimeBase), size);
311
312 /* save the serviceID */
313 connectionPrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
314
315 /* get the debug environment variable */
316 envdebug = getenv("PPPDebug");
317 if (envdebug) {
318 if (sscanf(envdebug, "%d", &connectionPrivate->debug) != 1)
319 connectionPrivate->debug = 1; /* PPPDebug value is invalid, set debug to 1 */
320 }
321
322 if (callout != NULL) {
323 connectionPrivate->rlsFunction = callout;
324
325 mach_context.info = (void*)connectionPrivate;
326 connectionPrivate->notify_port = CFMachPortCreate(NULL, __SCNetworkConnectionCallBack, &mach_context, NULL);
327 if (connectionPrivate->notify_port == NULL) {
328 goto fail;
329 }
330
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) {
336 goto fail;
337 }
338 }
339
340 if (context) {
341 bcopy(context, &connectionPrivate->rlsContext, sizeof(SCNetworkConnectionContext));
342 if (context->retain != NULL) {
343 connectionPrivate->rlsContext.info = (void *)(*context->retain)(context->info);
344 }
345 }
346
347 if (!_SCSerializeString(serviceID, &dataRef, &data, &dataLen)) {
348 goto fail;
349 }
350
351 status = bootstrap_unprivileged(bootstrap_port, &unpriv_bootstrap_port);
352 if (status != BOOTSTRAP_SUCCESS) {
353 goto fail;
354 }
355
356 status = pppcontroller_attach(server, data, dataLen, unpriv_bootstrap_port, notify_port,
357 &connectionPrivate->session_port, &error);
358
359 mach_port_deallocate(mach_task_self(), unpriv_bootstrap_port);
360 CFRelease(dataRef);
361 dataRef = NULL;
362
363 if (status != KERN_SUCCESS) {
364 goto fail;
365 }
366
367 if (error != kSCStatusOK) {
368 goto fail;
369 }
370
371 if (connectionPrivate->debug) {
372 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionCreate (0x%x) succeeded for service ID: %@"), connectionPrivate, serviceID);
373 }
374
375 /* success, return the connection reference */
376 return connectionPrivate;
377
378 fail:
379
380
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);
386 }
387
388 if (dataRef) CFRelease(dataRef);
389 _SCErrorSet(error);
390 return NULL;
391 }
392
393 /* -------------------------------------------------------------------------------------------
394 ------------------------------------------------------------------------------------------- */
395
396 CFTypeID
397 SCNetworkConnectionGetTypeID(void) {
398 pthread_once(&initialized, __SCNetworkConnectionInitialize); /* initialize runtime */
399 return __kSCNetworkConnectionTypeID;
400 }
401
402 /* -------------------------------------------------------------------------------------------
403 ------------------------------------------------------------------------------------------- */
404
405 SCNetworkConnectionRef
406 SCNetworkConnectionCreateWithServiceID(CFAllocatorRef allocator,
407 CFStringRef serviceID,
408 SCNetworkConnectionCallBack callout,
409 SCNetworkConnectionContext *context)
410 {
411 SCNetworkConnectionPrivateRef connectionPrivate;
412
413 if (!isA_CFString(serviceID)) {
414 _SCErrorSet(kSCStatusInvalidArgument);
415 return NULL;
416 }
417
418 connectionPrivate = __SCNetworkConnectionCreatePrivate(allocator, serviceID, callout, context);
419
420 return (SCNetworkConnectionRef)connectionPrivate;
421 }
422
423 /* -------------------------------------------------------------------------------------------
424 ------------------------------------------------------------------------------------------- */
425
426 CFStringRef
427 SCNetworkConnectionCopyServiceID(SCNetworkConnectionRef connection)
428 {
429 if (!isA_SCNetworkConnection(connection)) {
430 _SCErrorSet(kSCStatusInvalidArgument);
431 return NULL;
432 }
433
434 return CFRetain(((SCNetworkConnectionPrivateRef)connection)->serviceID);
435 }
436
437 /* -------------------------------------------------------------------------------------------
438 ------------------------------------------------------------------------------------------- */
439
440 CFDictionaryRef
441 SCNetworkConnectionCopyStatistics(SCNetworkConnectionRef connection)
442 {
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;
449
450 if (!isA_SCNetworkConnection(connection)) {
451 _SCErrorSet(kSCStatusInvalidArgument);
452 return NULL;
453 }
454
455 status = pppcontroller_copystatistics(connectionPrivate->session_port, &data, &datalen, &error);
456 if (status != KERN_SUCCESS) {
457 goto fail;
458 }
459
460 if (error != kSCStatusOK) {
461 goto fail;
462 }
463
464 if ((data == NULL) ||
465 !_SCUnserialize(&statistics, NULL, data, datalen) ||
466 !isA_CFDictionary(statistics)) {
467 goto fail;
468 }
469
470 return statistics;
471
472 fail:
473
474 if (statistics) CFRelease(statistics);
475 _SCErrorSet(error);
476 return NULL;
477 }
478
479 /* -------------------------------------------------------------------------------------------
480 ------------------------------------------------------------------------------------------- */
481
482 SCNetworkConnectionStatus
483 SCNetworkConnectionGetStatus(SCNetworkConnectionRef connection)
484 {
485 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
486 int error = kSCStatusFailed;
487 int phase;
488 SCNetworkConnectionStatus scstatus;
489 kern_return_t status;
490
491 if (!isA_SCNetworkConnection(connection)) {
492 _SCErrorSet(kSCStatusInvalidArgument);
493 return kSCNetworkConnectionInvalid;
494 }
495
496 status = pppcontroller_getstatus(connectionPrivate->session_port, &phase, &error);
497 if ((status != KERN_SUCCESS) || (error != kSCStatusOK)) {
498 return kSCNetworkConnectionDisconnected;
499 }
500
501 scstatus = __SCNetworkConnectionConvertStatus(phase);
502 return scstatus;
503 }
504
505 /* -------------------------------------------------------------------------------------------
506 ------------------------------------------------------------------------------------------- */
507
508 CFDictionaryRef
509 SCNetworkConnectionCopyExtendedStatus(SCNetworkConnectionRef connection)
510 {
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;
517
518 if (!isA_SCNetworkConnection(connection)) {
519 _SCErrorSet(kSCStatusInvalidArgument);
520 return NULL;
521 }
522
523 status = pppcontroller_copyextendedstatus(connectionPrivate->session_port, &data, &datalen, &error);
524 if (status != KERN_SUCCESS) {
525 goto fail;
526 }
527
528 if (error != kSCStatusOK) {
529 goto fail;
530 }
531
532 if ((data == NULL) ||
533 !_SCUnserialize(&extstatus, NULL, data, datalen) ||
534 !isA_CFDictionary(extstatus)) {
535 goto fail;
536 }
537
538 return extstatus;
539
540 fail:
541
542 if (extstatus) CFRelease(extstatus);
543 _SCErrorSet(error);
544 return NULL;
545 }
546
547 /* -------------------------------------------------------------------------------------------
548 ------------------------------------------------------------------------------------------- */
549
550 Boolean
551 SCNetworkConnectionStart(SCNetworkConnectionRef connection,
552 CFDictionaryRef userOptions,
553 Boolean linger)
554 {
555 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
556 CFDataRef dataref = NULL;
557 void *data = NULL;
558 CFIndex datalen = 0;
559 int error = kSCStatusFailed;
560 kern_return_t status;
561
562 if (!isA_SCNetworkConnection(connection)) {
563 _SCErrorSet(kSCStatusInvalidArgument);
564 return FALSE;
565 }
566
567 if (connectionPrivate->debug) {
568 CFMutableDictionaryRef mdict = NULL, mdict1;
569 CFDictionaryRef dict;
570
571 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionStart (0x%x)"), connectionPrivate);
572
573 if (userOptions) {
574 /* special code to remove secret information */
575 mdict = CFDictionaryCreateMutableCopy(0, 0, userOptions);
576 if (mdict) {
577 dict = CFDictionaryGetValue(mdict, kSCEntNetPPP);
578 if (isA_CFDictionary(dict)) {
579 mdict1 = CFDictionaryCreateMutableCopy(0, 0, dict);
580 if (mdict1) {
581 CFDictionaryReplaceValue(mdict1, kSCPropNetPPPAuthPassword, CFSTR("******"));
582 CFDictionarySetValue(mdict, kSCEntNetPPP, mdict1);
583 CFRelease(mdict1);
584 }
585 }
586
587 dict = CFDictionaryGetValue(mdict, kSCEntNetL2TP);
588 if (isA_CFDictionary(dict)) {
589 mdict1 = CFDictionaryCreateMutableCopy(0, 0, dict);
590 if (mdict1) {
591 CFDictionaryReplaceValue(mdict1, kSCPropNetL2TPIPSecSharedSecret, CFSTR("******"));
592 CFDictionarySetValue(mdict, kSCEntNetL2TP, mdict1);
593 CFRelease(mdict1);
594 }
595 }
596
597 dict = CFDictionaryGetValue(mdict, kSCEntNetIPSec);
598 if (isA_CFDictionary(dict)) {
599 mdict1 = CFDictionaryCreateMutableCopy(0, 0, dict);
600 if (mdict1) {
601 CFDictionaryReplaceValue(mdict1, kSCPropNetIPSecSharedSecret, CFSTR("******"));
602 CFDictionarySetValue(mdict, kSCEntNetIPSec, mdict1);
603 CFRelease(mdict1);
604 }
605 }
606 }
607 }
608
609 SCLog(TRUE, LOG_DEBUG, CFSTR("User options: %@"), mdict);
610 if (mdict)
611 CFRelease(mdict);
612 }
613
614 if (userOptions && !_SCSerialize(userOptions, &dataref, &data, &datalen)) {
615 goto fail;
616 }
617
618 status = pppcontroller_start(connectionPrivate->session_port, data, datalen, linger, &error);
619 if (status != KERN_SUCCESS) {
620 goto fail;
621 }
622
623 if (dataref) {
624 CFRelease(dataref);
625 dataref = NULL;
626 }
627
628 if (connectionPrivate->debug)
629 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionStart (0x%x), return: %d"), connectionPrivate, error);
630
631 if (error != kSCStatusOK) {
632 goto fail;
633 }
634
635 /* connection is now started */
636 return TRUE;
637
638 fail:
639
640 if (dataref) CFRelease(dataref);
641 _SCErrorSet(error);
642 return FALSE;
643 }
644
645 /* -------------------------------------------------------------------------------------------
646 ------------------------------------------------------------------------------------------- */
647
648 Boolean
649 SCNetworkConnectionStop(SCNetworkConnectionRef connection,
650 Boolean forceDisconnect)
651 {
652 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
653 int error = kSCStatusFailed;
654 kern_return_t status;
655
656 if (!isA_SCNetworkConnection(connection)) {
657 _SCErrorSet(kSCStatusInvalidArgument);
658 return FALSE;
659 }
660
661 if (connectionPrivate->debug)
662 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionStop (0x%x)"), connectionPrivate);
663
664 status = pppcontroller_stop(connectionPrivate->session_port, forceDisconnect, &error);
665 if (status != KERN_SUCCESS) {
666 goto fail;
667 }
668
669 if (connectionPrivate->debug)
670 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionStop (0x%x), return: %d"), connectionPrivate, error);
671
672 if (error != kSCStatusOK) {
673 goto fail;
674 }
675
676 /* connection is now disconnecting */
677 return TRUE;
678
679 fail:
680
681 _SCErrorSet(error);
682 return FALSE;
683 }
684
685 /* -------------------------------------------------------------------------------------------
686 ------------------------------------------------------------------------------------------- */
687
688 Boolean
689 SCNetworkConnectionSuspend(SCNetworkConnectionRef connection)
690 {
691 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
692 int error = kSCStatusFailed;
693 kern_return_t status;
694
695 if (!isA_SCNetworkConnection(connection)) {
696 _SCErrorSet(kSCStatusInvalidArgument);
697 return FALSE;
698 }
699
700 if (connectionPrivate->debug)
701 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionSuspend (0x%x)"), connectionPrivate);
702
703 status = pppcontroller_suspend(connectionPrivate->session_port, &error);
704 if (status != KERN_SUCCESS) {
705 goto fail;
706 }
707
708 if (connectionPrivate->debug)
709 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionSuspend (0x%x), return: %d"), connectionPrivate, error);
710
711 if (error != kSCStatusOK) {
712 goto fail;
713 }
714
715 /* connection is now suspended */
716 return TRUE;
717
718 fail:
719
720 _SCErrorSet(error);
721 return FALSE;
722 }
723
724 /* -------------------------------------------------------------------------------------------
725 ------------------------------------------------------------------------------------------- */
726
727 Boolean
728 SCNetworkConnectionResume(SCNetworkConnectionRef connection)
729 {
730 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
731 int error = kSCStatusFailed;
732 kern_return_t status;
733
734 if (!isA_SCNetworkConnection(connection)) {
735 _SCErrorSet(kSCStatusInvalidArgument);
736 return FALSE;
737 }
738
739 if (connectionPrivate->debug)
740 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionResume (0x%x)"), connectionPrivate);
741
742 status = pppcontroller_resume(connectionPrivate->session_port, &error);
743 if (status != KERN_SUCCESS) {
744 goto fail;
745 }
746
747 if (connectionPrivate->debug)
748 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionResume (0x%x), return: %d"), connectionPrivate, error);
749
750 if (error != kSCStatusOK) {
751 goto fail;
752 }
753
754 /* connection is now resume */
755 return TRUE;
756
757 fail:
758
759 _SCErrorSet(error);
760 return FALSE;
761 }
762
763 /* -------------------------------------------------------------------------------------------
764 ------------------------------------------------------------------------------------------- */
765
766 CFDictionaryRef
767 SCNetworkConnectionCopyUserOptions(SCNetworkConnectionRef connection)
768 {
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;
775
776 if (!isA_SCNetworkConnection(connection)) {
777 _SCErrorSet(kSCStatusInvalidArgument);
778 return NULL;
779 }
780
781 status = pppcontroller_copyuseroptions(connectionPrivate->session_port, &data, &datalen, &error);
782 if (status != KERN_SUCCESS) {
783 goto fail;
784 }
785
786 if (error != kSCStatusOK) {
787 goto fail;
788 }
789
790 // no data were used, return an empty dictionary
791 if (data == NULL) {
792 CFDictionaryRef dict;
793
794 dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
795 if (dict == NULL) {
796 _SCErrorSet(kSCStatusFailed); // XXX
797 }
798 return dict;
799 }
800
801 if (!_SCUnserialize(&userOptions, NULL, data, datalen) ||
802 !isA_CFDictionary(userOptions)) {
803 goto fail;
804 }
805
806 return userOptions;
807
808 fail:
809
810 if (userOptions) CFRelease(userOptions);
811 _SCErrorSet(error);
812 return NULL;
813 }
814
815 /* -------------------------------------------------------------------------------------------
816 ------------------------------------------------------------------------------------------- */
817
818 Boolean
819 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection,
820 CFRunLoopRef runLoop,
821 CFStringRef runLoopMode)
822 {
823 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
824 int error = kSCStatusFailed;
825 kern_return_t status;
826
827 if (!isA_SCNetworkConnection(connection) || runLoop == NULL || runLoopMode == NULL) {
828 _SCErrorSet(kSCStatusInvalidArgument);
829 return FALSE;
830 }
831
832 if (connectionPrivate->rlsFunction == NULL) {
833 _SCErrorSet(kSCStatusInvalidArgument);
834 return FALSE;
835 }
836
837 if ((connectionPrivate->rlList != NULL) &&
838 _SC_isScheduled(NULL, runLoop, runLoopMode, connectionPrivate->rlList)) {
839 /* already scheduled */
840 _SCErrorSet(kSCStatusFailed);
841 return FALSE;
842 }
843
844 if (connectionPrivate->rlList == NULL) {
845 status = pppcontroller_notification(connectionPrivate->session_port, 1, &error);
846 if ((status != KERN_SUCCESS) || (error != kSCStatusOK)) {
847 _SCErrorSet(error);
848 return FALSE;
849 }
850
851 connectionPrivate->rls = CFMachPortCreateRunLoopSource(NULL, connectionPrivate->notify_port, 0);
852 connectionPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
853 }
854
855 CFRunLoopAddSource(runLoop, connectionPrivate->rls, runLoopMode);
856 _SC_schedule(connectionPrivate, runLoop, runLoopMode, connectionPrivate->rlList);
857
858 return TRUE;
859 }
860
861 /* -------------------------------------------------------------------------------------------
862 ------------------------------------------------------------------------------------------- */
863
864 Boolean
865 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection,
866 CFRunLoopRef runLoop,
867 CFStringRef runLoopMode)
868 {
869 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
870 int error = kSCStatusFailed;
871 kern_return_t status;
872
873 if (!isA_SCNetworkConnection(connection) || runLoop == NULL || runLoopMode == NULL) {
874 _SCErrorSet(kSCStatusInvalidArgument);
875 return FALSE;
876 }
877
878 if ((connectionPrivate->rlList == NULL) ||
879 !_SC_unschedule(connectionPrivate, runLoop, runLoopMode, connectionPrivate->rlList, FALSE)) {
880 /* if not currently scheduled */
881 _SCErrorSet(kSCStatusFailed);
882 return FALSE;
883 }
884
885 CFRunLoopRemoveSource(runLoop, connectionPrivate->rls, runLoopMode);
886
887 if (CFArrayGetCount(connectionPrivate->rlList) == 0) {
888 CFRelease(connectionPrivate->rls);
889 connectionPrivate->rls = NULL;
890 CFRelease(connectionPrivate->rlList);
891 connectionPrivate->rlList = NULL;
892
893 status = pppcontroller_notification(connectionPrivate->session_port, 0, &error);
894 if ((status != KERN_SUCCESS) || (error != kSCStatusOK)) {
895 _SCErrorSet(error);
896 return FALSE;
897 }
898 }
899
900 return TRUE;
901 }
902
903
904 //************************* USER LEVEL DIAL API **********************************
905
906
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")
910
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")
914
915
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);
924
925 static int notify_userprefs_token = -1;
926
927 /*
928 * return TRUE if domain1 ends with domain2, and will check for trailing "."
929 */
930 static Boolean
931 domainEndsWithDomain(CFStringRef domain1, CFStringRef domain2)
932 {
933 CFRange range;
934 Boolean ret = FALSE;
935 CFStringRef s1 = NULL;
936 Boolean s1_created = FALSE;
937 CFStringRef s2 = NULL;
938 Boolean s2_created = FALSE;
939
940 if (CFStringHasSuffix(domain1, CFSTR("."))) {
941 range.location = 0;
942 range.length = CFStringGetLength(domain1) - 1;
943 s1 = CFStringCreateWithSubstring(NULL, domain1, range);
944 if (s1 == NULL) {
945 goto done;
946 }
947 s1_created = TRUE;
948 } else {
949 s1 = domain1;
950 }
951
952 if (CFStringHasSuffix(domain2, CFSTR("."))) {
953 range.location = 0;
954 range.length = CFStringGetLength(domain2) - 1;
955 s2 = CFStringCreateWithSubstring(NULL, domain2, range);
956 if (s2 == NULL) {
957 goto done;
958 }
959 s2_created = TRUE;
960 } else {
961 s2 = domain2;
962 }
963
964 ret = CFStringHasSuffix(s1, s2);
965
966 done :
967
968 if (s1_created) CFRelease(s1);
969 if (s2_created) CFRelease(s2);
970 return ret;
971 }
972
973
974 Boolean
975 SCNetworkConnectionCopyUserPreferences(CFDictionaryRef selectionOptions,
976 CFStringRef *serviceID,
977 CFDictionaryRef *userOptions)
978 {
979 int debug = 0;
980 char *envdebug;
981 int prefsChanged;
982 SCDynamicStoreRef session;
983 Boolean success = FALSE;
984 int status;
985
986 envdebug = getenv("PPPDebug");
987 if (envdebug) {
988 if (sscanf(envdebug, "%d", &debug) != 1)
989 debug = 1; /* PPPDebug value is invalid, set debug to 1 */
990 }
991
992 if (notify_userprefs_token == -1) {
993 status = notify_register_check(k_NetworkConnect_Notification, &notify_userprefs_token);
994 if (status != NOTIFY_STATUS_OK)
995 notify_userprefs_token = -1;
996 else
997 // clear the flag
998 notify_check(notify_userprefs_token, &prefsChanged);
999 }
1000
1001 prefsChanged = 1;
1002 if (notify_userprefs_token != -1)
1003 notify_check(notify_userprefs_token, &prefsChanged);
1004
1005
1006 // NOTE: we are currently ignoring selectionOptions
1007
1008 *serviceID = NULL;
1009 *userOptions = NULL;
1010
1011 session = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkConnection"), NULL, NULL);
1012 if (session == NULL) {
1013 fprintf(stderr, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
1014 return FALSE;
1015 }
1016
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;
1027
1028 hostName = CFDictionaryGetValue(selectionOptions, kSCPropNetPPPOnDemandHostName);
1029 if (!isA_CFString(hostName))
1030 hostName = NULL;
1031
1032 // can't select anything
1033 if (hostName == NULL)
1034 goto done_selection;
1035
1036 priority = CFDictionaryGetValue(selectionOptions, kSCPropNetPPPOnDemandPriority);
1037 if (!isA_CFString(priority))
1038 priority = kSCValNetPPPOnDemandPriorityDefault;
1039
1040
1041 if (!isA_CFArray(serviceNames))
1042 goto done_selection;
1043
1044
1045 if (!isA_CFDictionary(services))
1046 goto done_selection;
1047
1048 servicesCount = CFArrayGetCount(serviceNames);
1049 for (serviceIndex = 0; serviceIndex < servicesCount; serviceIndex++) {
1050 CFIndex configIndex;
1051 CFIndex configsCount;
1052 CFArrayRef serviceConfigs;
1053 CFStringRef serviceName;
1054 int val;
1055
1056 serviceName = CFArrayGetValueAtIndex(serviceNames, serviceIndex);
1057 if (!isA_CFString(serviceName))
1058 continue;
1059
1060 serviceConfigs = CFDictionaryGetValue(services, serviceName);
1061 if (!isA_CFArray(serviceConfigs))
1062 continue;
1063
1064 configsCount = CFArrayGetCount(serviceConfigs);
1065 for (configIndex = 0; configIndex < configsCount; configIndex++) {
1066 CFNumberRef autodial;
1067 CFDictionaryRef config;
1068 CFDictionaryRef pppConfig;
1069
1070 config = CFArrayGetValueAtIndex(serviceConfigs, configIndex);
1071 if (!isA_CFDictionary(config))
1072 continue;
1073
1074 pppConfig = CFDictionaryGetValue(config, kSCEntNetPPP);
1075 if (!isA_CFDictionary(pppConfig))
1076 continue;
1077
1078 autodial = CFDictionaryGetValue(pppConfig, kSCPropNetPPPOnDemandEnabled);
1079 if (!isA_CFNumber(autodial))
1080 continue;
1081
1082 CFNumberGetValue(autodial, kCFNumberIntType, &val);
1083 if (val) {
1084 CFArrayRef autoDomains;
1085 CFIndex domainIndex;
1086 CFIndex domainsCount;
1087
1088 /* we found an conditional connection enabled configuration */
1089
1090 /* check domain */
1091 autoDomains = CFDictionaryGetValue(pppConfig, kSCPropNetPPPOnDemandDomains);
1092 if (!isA_CFArray(autoDomains))
1093 continue;
1094
1095 domainsCount = CFArrayGetCount(autoDomains);
1096 for (domainIndex = 0; domainIndex < domainsCount; domainIndex++) {
1097 CFStringRef domain;
1098
1099 domain = CFArrayGetValueAtIndex(autoDomains, domainIndex);
1100 if (!isA_CFString(domain))
1101 continue;
1102
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;
1110 }
1111
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);
1120 success = TRUE;
1121 goto done_selection;
1122 }
1123 }
1124 }
1125 }
1126 }
1127
1128 // config not found, do we have a catchall ?
1129 if (catchAllFound) {
1130 CFDictionaryRef config;
1131 CFArrayRef serviceConfigs;
1132 CFStringRef serviceName;
1133
1134 serviceName = CFArrayGetValueAtIndex(serviceNames, catchAllService);
1135 serviceConfigs = CFDictionaryGetValue(services, serviceName);
1136 config = CFArrayGetValueAtIndex(serviceConfigs, catchAllConfig);
1137
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);
1144 success = TRUE;
1145 goto done_selection;
1146 }
1147
1148 done_selection:
1149
1150 if (serviceNames)
1151 CFRelease(serviceNames);
1152 if (services)
1153 CFRelease(services);
1154 CFRelease(session);
1155
1156 if (debug > 1) {
1157 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionCopyUserPreferences %@"), success ? CFSTR("succeeded") : CFSTR("failed"));
1158 SCLog(TRUE, LOG_DEBUG, CFSTR("Selection options: %@"), selectionOptions);
1159 }
1160
1161 return success;
1162 }
1163
1164 /* we don't have selection options */
1165
1166 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
1167 success = SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session, serviceID);
1168
1169 if (success && (*serviceID != NULL)) {
1170 // (2) Get the list of user data for this service ID
1171 CFPropertyListRef userServices = NULL;
1172
1173
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,
1179 userOptions);
1180 if(success && (userOptions != NULL)) {
1181 addPasswordFromKeychain(session, *serviceID, userOptions);
1182 }
1183 } else {
1184 fprintf(stderr, "Error, userServices are not of type CFArray!\n");
1185 }
1186
1187 CFRelease(userServices); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
1188 }
1189 }
1190
1191 if (debug > 1) {
1192 SCLog(TRUE, LOG_DEBUG, CFSTR("SCNetworkConnectionCopyUserPreferences %@, no selection options"), success ? CFSTR("succeeded") : CFSTR("failed"));
1193 }
1194
1195 CFRelease(session);
1196 return success;
1197 }
1198
1199
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 //********************************************************************************************
1207 static Boolean
1208 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session, CFStringRef *serviceID)
1209 {
1210 Boolean foundService = FALSE;
1211 CFPropertyListRef lastServiceSelectedInIC = NULL;
1212
1213
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;
1220 CFStringRef key;
1221
1222 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1223 kSCDynamicStoreDomainSetup,
1224 lastServiceSelectedInIC,
1225 kSCEntNetInterface);
1226 dict = SCDynamicStoreCopyValue(session, key);
1227 CFRelease(key);
1228 if (dict != NULL) {
1229 CFRelease(dict);
1230 *serviceID = CFRetain(lastServiceSelectedInIC);
1231 foundService = TRUE;
1232 }
1233 }
1234 CFRelease(lastServiceSelectedInIC);
1235 }
1236
1237 if (!foundService) {
1238 foundService = SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session, serviceID);
1239 }
1240
1241 return foundService;
1242 }
1243
1244 //********************************************************************************
1245 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
1246 // -------------------------------------------------------
1247 // Find the highest ordered PPP service in the dynamic store
1248 //********************************************************************************
1249 static Boolean
1250 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session, CFStringRef *serviceID)
1251 {
1252 CFDictionaryRef dict = NULL;
1253 CFStringRef key = NULL;
1254 CFArrayRef serviceIDs = NULL;
1255 Boolean success = FALSE;
1256
1257 *serviceID = NULL;
1258
1259 do {
1260 CFIndex count;
1261 CFIndex i;
1262
1263 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, kSCEntNetIPv4);
1264 if (key == NULL) {
1265 fprintf(stderr, "Error, Setup Key == NULL!\n");
1266 break;
1267 }
1268
1269 dict = SCDynamicStoreCopyValue(session, key);
1270 if (!isA_CFDictionary(dict)) {
1271 fprintf(stderr, "no global IPv4 entity\n");
1272 break;
1273 }
1274
1275 serviceIDs = CFDictionaryGetValue(dict, kSCPropNetServiceOrder); // array of service id's
1276 if (!isA_CFArray(serviceIDs)) {
1277 fprintf(stderr, "service order not specified\n");
1278 break;
1279 }
1280
1281 count = CFArrayGetCount(serviceIDs);
1282 for (i = 0; i < count; i++) {
1283 CFStringRef service = CFArrayGetValueAtIndex(serviceIDs, i);
1284
1285 if (SCNetworkConnectionPrivateIsPPPService(session, service, kSCValNetInterfaceSubTypePPPSerial, kSCValNetInterfaceSubTypePPPoE)) {
1286 *serviceID = CFRetain(service);
1287 success = TRUE;
1288 break;
1289 }
1290 }
1291 } while (FALSE);
1292
1293 if (key != NULL) CFRelease(key);
1294 if (dict != NULL) CFRelease(dict);
1295
1296 return success;
1297 }
1298
1299 //********************************************************************************
1300 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
1301 // ---------------------------------------------------------
1302 // Copy over user preferences for a particular service if they exist
1303 //********************************************************************************
1304 static Boolean
1305 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray, CFDictionaryRef *userOptions)
1306 {
1307 CFIndex count = CFArrayGetCount(userOptionsArray);
1308 int i;
1309
1310 for (i = 0; i < count; i++) {
1311 // (1) Find the dictionary
1312 CFPropertyListRef propertyList = CFArrayGetValueAtIndex(userOptionsArray, i);
1313
1314 if (isA_CFDictionary(propertyList) != NULL) {
1315 // See if there's a value for dial on demand
1316 CFPropertyListRef value;
1317
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);
1324 break;
1325 }
1326 }
1327 }
1328 }
1329
1330 return TRUE;
1331 }
1332
1333 //********************************************************************************
1334 // SCNetworkConnectionPrivateIsServiceType
1335 // --------------------------------------
1336 // Check and see if the service is a PPP service of the given types
1337 //********************************************************************************
1338 static Boolean
1339 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session, CFStringRef serviceID, CFStringRef subType1, CFStringRef subType2)
1340 {
1341 CFStringRef entityKey;
1342 Boolean isPPPService = FALSE;
1343 Boolean isMatchingSubType = FALSE;
1344 CFDictionaryRef serviceDict;
1345
1346 entityKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1347 kSCDynamicStoreDomainSetup,
1348 serviceID,
1349 kSCEntNetInterface);
1350 if (entityKey == NULL) {
1351 return FALSE;
1352 }
1353
1354 serviceDict = SCDynamicStoreCopyValue(session, entityKey);
1355 if (serviceDict != NULL) {
1356 if (isA_CFDictionary(serviceDict)) {
1357 CFStringRef type;
1358 CFStringRef subtype;
1359
1360 type = CFDictionaryGetValue(serviceDict, kSCPropNetInterfaceType);
1361 if (isA_CFString(type)) {
1362 isPPPService = CFEqual(type, kSCValNetInterfaceTypePPP);
1363 }
1364
1365 subtype = CFDictionaryGetValue(serviceDict, kSCPropNetInterfaceSubType);
1366 if (isA_CFString(subtype)) {
1367 isMatchingSubType = CFEqual(subtype, subType1);
1368 if (!isMatchingSubType && subType2)
1369 isMatchingSubType = CFEqual(subtype, subType2);
1370 }
1371 }
1372 CFRelease(serviceDict);
1373 }
1374 CFRelease(entityKey);
1375
1376 return (isPPPService && isMatchingSubType);
1377 }
1378
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 //********************************************************************************
1385 static void
1386 addPasswordFromKeychain(SCDynamicStoreRef session, CFStringRef serviceID, CFDictionaryRef *userOptions)
1387 {
1388 CFPropertyListRef uniqueID;
1389 CFStringRef password;
1390 CFStringRef sharedsecret = NULL;
1391
1392 /* user options must exist */
1393 if (*userOptions == NULL)
1394 return;
1395
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))
1399 return;
1400
1401 /* first, get the PPP password */
1402 password = copyPasswordFromKeychain(uniqueID);
1403
1404 /* then, if necessary, get the IPSec Shared Secret */
1405 if (SCNetworkConnectionPrivateIsPPPService(session, serviceID, kSCValNetInterfaceSubTypeL2TP, 0)) {
1406 CFMutableStringRef uniqueIDSS;
1407
1408 uniqueIDSS = CFStringCreateMutableCopy(NULL, 0, uniqueID);
1409 CFStringAppend(uniqueIDSS, CFSTR(".SS"));
1410 sharedsecret = copyPasswordFromKeychain(uniqueIDSS);
1411 CFRelease(uniqueIDSS);
1412 }
1413
1414 /* did we find our information in the key chain ? */
1415 if ((password != NULL) || (sharedsecret != NULL)) {
1416 CFMutableDictionaryRef newOptions;
1417
1418 newOptions = CFDictionaryCreateMutableCopy(NULL, 0, *userOptions);
1419
1420 /* PPP password */
1421 if (password != NULL) {
1422 CFDictionaryRef entity;
1423 CFMutableDictionaryRef newEntity;
1424
1425 entity = CFDictionaryGetValue(*userOptions, kSCEntNetPPP);
1426 if (isA_CFDictionary(entity))
1427 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1428 else
1429 newEntity = CFDictionaryCreateMutable(NULL,
1430 0,
1431 &kCFTypeDictionaryKeyCallBacks,
1432 &kCFTypeDictionaryValueCallBacks);
1433
1434
1435 /* set the PPP password */
1436 CFDictionarySetValue(newEntity, kSCPropNetPPPAuthPassword, password);
1437 CFRelease(password);
1438
1439 /* update the PPP entity */
1440 CFDictionarySetValue(newOptions, kSCEntNetPPP, newEntity);
1441 CFRelease(newEntity);
1442 }
1443
1444 /* IPSec Shared Secret */
1445 if (sharedsecret != NULL) {
1446 CFDictionaryRef entity;
1447 CFMutableDictionaryRef newEntity;
1448
1449 entity = CFDictionaryGetValue(*userOptions, kSCEntNetIPSec);
1450 if (isA_CFDictionary(entity))
1451 newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity);
1452 else
1453 newEntity = CFDictionaryCreateMutable(NULL,
1454 0,
1455 &kCFTypeDictionaryKeyCallBacks,
1456 &kCFTypeDictionaryValueCallBacks);
1457
1458 /* set the IPSec Shared Secret */
1459 CFDictionarySetValue(newEntity, kSCPropNetIPSecSharedSecret, sharedsecret);
1460 CFRelease(sharedsecret);
1461
1462 /* update the IPSec entity */
1463 CFDictionarySetValue(newOptions, kSCEntNetIPSec, newEntity);
1464 CFRelease(newEntity);
1465 }
1466
1467 /* update the userOptions dictionary */
1468 CFRelease(*userOptions);
1469 *userOptions = CFDictionaryCreateCopy(NULL, newOptions);
1470 CFRelease(newOptions);
1471 }
1472
1473 }
1474
1475 //********************************************************************************
1476 // copyPasswordFromKeychain
1477 // --------------------------------------
1478 // Given a uniqueID, retrieve the password from the keychain
1479 //********************************************************************************
1480 static CFStringRef
1481 copyPasswordFromKeychain(CFStringRef uniqueID)
1482 {
1483 CFArrayRef enumerator;
1484 CFIndex n;
1485 CFStringRef password = NULL;
1486
1487 enumerator = copyKeychainEnumerator(uniqueID);
1488 if (enumerator == NULL) {
1489 return NULL; // if no keychain enumerator
1490 }
1491
1492 n = CFArrayGetCount(enumerator);
1493 if (n > 0) {
1494 void *data = NULL;
1495 UInt32 dataLen = 0;
1496 SecKeychainItemRef itemRef;
1497 OSStatus result;
1498
1499 itemRef = (SecKeychainItemRef)CFArrayGetValueAtIndex(enumerator, 0);
1500 result = SecKeychainItemCopyContent(itemRef, // itemRef
1501 NULL, // itemClass
1502 NULL, // attrList
1503 &dataLen, // length
1504 (void *)&data); // outData
1505 if ((result == noErr) && (data != NULL) && (dataLen > 0)) {
1506 password = CFStringCreateWithBytes(NULL, data, dataLen, kCFStringEncodingUTF8, TRUE);
1507 }
1508 }
1509
1510 CFRelease(enumerator);
1511
1512 return password;
1513 }
1514
1515 //********************************************************************************
1516 // copyKeychainEnumerator
1517 // --------------------------------------
1518 // Gather Keychain Enumerator
1519 //********************************************************************************
1520 static CFArrayRef
1521 copyKeychainEnumerator(CFStringRef uniqueIdentifier)
1522 {
1523 char *buf;
1524 CFMutableArrayRef itemArray = NULL;
1525 OSStatus result;
1526 SecKeychainSearchRef search = NULL;
1527
1528 buf = _SC_cfstring_to_cstring(uniqueIdentifier, NULL, 0, kCFStringEncodingUTF8);
1529 if (buf != NULL) {
1530 // search for unique identifier in "svce" attribute
1531 SecKeychainAttribute attributes[] = {{ kSecServiceItemAttr,
1532 CFStringGetLength(uniqueIdentifier),
1533 (void *)buf
1534 }};
1535
1536 SecKeychainAttributeList attrList = { sizeof(attributes) / sizeof(*attributes),
1537 attributes };
1538
1539 result = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attrList, &search);
1540 if (result == noErr) {
1541 itemArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1542
1543 while (result == noErr) {
1544 SecKeychainItemRef itemFound = NULL;
1545
1546 result = SecKeychainSearchCopyNext(search, &itemFound);
1547 if (result != noErr) {
1548 break;
1549 }
1550
1551 if (itemFound) {
1552 CFArrayAppendValue(itemArray, itemFound);
1553 CFRelease(itemFound);
1554 }
1555 }
1556 }
1557 }
1558
1559 if (search) CFRelease(search);
1560 if (buf) CFAllocatorDeallocate(NULL, buf);
1561
1562 return itemArray;
1563 }