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