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