]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCNetworkConnection.c
configd-84.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCNetworkConnection.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Modification History
28 *
29 * December 20, 2002 Christophe Allie <callie@apple.com>
30 * - initial revision
31 */
32
33 /* -------------------------------------------------------------------------------------------
34 ------------------------------------------------------------------------------------------- */
35
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <CoreFoundation/CFRuntime.h>
38
39 #include <Security/Security.h>
40 #include "dy_framework.h"
41
42 #include <SystemConfiguration/SystemConfiguration.h>
43 #include <SystemConfiguration/SCPrivate.h>
44 #include <SystemConfiguration/SCValidation.h>
45
46 #include <pthread.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49 #include <arpa/nameser.h>
50 #include <netdb.h>
51 #include <resolv.h>
52 #include <unistd.h>
53 #include <sys/ioctl.h>
54 #include <sys/socket.h>
55 #include <net/if.h>
56
57 #include "ppp.h"
58
59
60 /* -------------------------------------------------------------------------------------------
61 ------------------------------------------------------------------------------------------- */
62
63 typedef struct {
64
65 /* base CFType information */
66 CFRuntimeBase cfBase;
67
68 /* service ID */
69 CFStringRef serviceID; /* serviceID */
70
71 int eventRef; /* ref to PPP controller for event messages */
72 CFSocketRef eventRefCF; /* ref to PPP controller for event messages */
73 int controlRef; /* ref to PPP controller for control messages */
74 //u_int32_t status; /* current status of the connection */
75 //char ifname[IFNAMSIZ]; /* ppp interface used for this connection */
76
77 /* run loop source, callout, context, rl scheduling info */
78 CFRunLoopSourceRef rls;
79 SCNetworkConnectionCallBack rlsFunction;
80 SCNetworkConnectionContext rlsContext;
81 CFMutableArrayRef rlList;
82
83 } SCNetworkConnectionPrivate, *SCNetworkConnectionPrivateRef;
84
85 /* -------------------------------------------------------------------------------------------
86 ------------------------------------------------------------------------------------------- */
87
88 static __inline__ CFTypeRef
89 isA_SCNetworkConnection(CFTypeRef obj)
90 {
91 return (isA_CFType(obj, SCNetworkConnectionGetTypeID()));
92 }
93
94 /* -------------------------------------------------------------------------------------------
95 ------------------------------------------------------------------------------------------- */
96
97 static CFStringRef
98 __SCNetworkConnectionCopyDescription(CFTypeRef cf)
99 {
100 CFAllocatorRef allocator = CFGetAllocator(cf);
101 CFMutableStringRef result;
102 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)cf;
103
104 result = CFStringCreateMutable(allocator, 0);
105 CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkConnection, %p [%p]> {\n"), cf, allocator);
106 CFStringAppendFormat(result, NULL, CFSTR(" serviceID = %@ \n"), connectionPrivate->serviceID);
107 CFStringAppendFormat(result, NULL, CFSTR("}"));
108
109 return result;
110 }
111
112 /* -------------------------------------------------------------------------------------------
113 ------------------------------------------------------------------------------------------- */
114 static void
115 __SCNetworkConnectionDeallocate(CFTypeRef cf)
116 {
117 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)cf;
118
119 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkConnectionDeallocate:"));
120
121 /* release resources */
122 if (connectionPrivate->eventRef != -1) {
123 while (CFArrayGetCount(connectionPrivate->rlList)) {
124 CFRunLoopRef runLoop;
125 CFStringRef runLoopMode;
126
127 runLoop = (CFRunLoopRef)CFArrayGetValueAtIndex(connectionPrivate->rlList, 1);
128 runLoopMode = CFArrayGetValueAtIndex(connectionPrivate->rlList, 2);
129 CFRunLoopRemoveSource(runLoop, connectionPrivate->rls, runLoopMode);
130
131 CFArrayRemoveValueAtIndex(connectionPrivate->rlList, 2);
132 CFArrayRemoveValueAtIndex(connectionPrivate->rlList, 1);
133 CFArrayRemoveValueAtIndex(connectionPrivate->rlList, 0);
134 }
135 CFRelease(connectionPrivate->rls);
136 CFRelease(connectionPrivate->rlList);
137 //PPPDispose(connectionPrivate->eventRef);
138 CFSocketInvalidate(connectionPrivate->eventRefCF);
139 CFRelease(connectionPrivate->eventRefCF);
140 }
141 if (connectionPrivate->controlRef != -1)
142 PPPDispose(connectionPrivate->controlRef);
143 if (connectionPrivate->rlsContext.release)
144 connectionPrivate->rlsContext.release(connectionPrivate->rlsContext.info);
145 if (connectionPrivate->serviceID)
146 CFRelease(connectionPrivate->serviceID);
147
148 return;
149 }
150
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 ------------------------------------------------------------------------------------------- */
172
173 static void
174 __SCNetworkConnectionInitialize(void)
175 {
176 __kSCNetworkConnectionTypeID = _CFRuntimeRegisterClass(&__SCNetworkConnectionClass);
177 return;
178 }
179
180 /* -------------------------------------------------------------------------------------------
181 ------------------------------------------------------------------------------------------- */
182 static SCNetworkConnectionPrivateRef
183 __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator, CFStringRef serviceID)
184 {
185 SCNetworkConnectionPrivateRef connectionPrivate = 0;
186 uint32_t size;
187 struct ppp_status *stats = 0;
188 int error = kSCStatusFailed;
189
190 /* initialize runtime */
191 pthread_once(&initialized, __SCNetworkConnectionInitialize);
192
193 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkConnectionCreatePrivate:"));
194
195 /* allocate NetworkConnection */
196 size = sizeof(SCNetworkConnectionPrivate) - sizeof(CFRuntimeBase);
197 connectionPrivate = (SCNetworkConnectionPrivateRef)_CFRuntimeCreateInstance(allocator, __kSCNetworkConnectionTypeID,size, NULL);
198 if (connectionPrivate == 0)
199 goto fail;
200
201 /* zero the data structure */
202 bzero(((u_char*)connectionPrivate)+sizeof(CFRuntimeBase), size);
203
204 /* save the serviceID */
205 connectionPrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
206
207 connectionPrivate->controlRef = -1;
208 connectionPrivate->eventRef = -1;
209
210 if (PPPInit(&connectionPrivate->controlRef))
211 goto fail;
212
213 if (PPPStatus(connectionPrivate->controlRef, serviceID, 0, &stats)) {
214 error = kSCStatusInvalidArgument; // XXX can't get status, invalid service id
215 goto fail;
216 }
217
218 CFAllocatorDeallocate(NULL, stats);
219 stats = 0;
220
221 /* success, return the connection reference */
222 return connectionPrivate;
223
224 fail:
225
226 /* failure, clean up and leave */
227 if (connectionPrivate)
228 CFRelease(connectionPrivate);
229 if (stats)
230 CFAllocatorDeallocate(NULL, stats);
231 _SCErrorSet(error);
232 return NULL;
233 }
234
235 /* -------------------------------------------------------------------------------------------
236 ------------------------------------------------------------------------------------------- */
237
238 CFTypeID
239 SCNetworkConnectionGetTypeID (void) {
240 pthread_once(&initialized, __SCNetworkConnectionInitialize); /* initialize runtime */
241 return __kSCNetworkConnectionTypeID;
242 }
243
244 /* -------------------------------------------------------------------------------------------
245 ------------------------------------------------------------------------------------------- */
246 static SCNetworkConnectionStatus
247 __SCNetworkConnectionConvertStatus (int state)
248 {
249 SCNetworkConnectionStatus status = kSCNetworkConnectionDisconnected;
250
251 switch (state) {
252 case PPP_INITIALIZE:
253 case PPP_CONNECTLINK:
254 case PPP_ESTABLISH:
255 case PPP_AUTHENTICATE:
256 case PPP_CALLBACK:
257 case PPP_NETWORK:
258 case PPP_WAITONBUSY:
259 status = kSCNetworkConnectionConnecting;
260 break;
261 case PPP_TERMINATE:
262 case PPP_DISCONNECTLINK:
263 case PPP_HOLDOFF:
264 status = kSCNetworkConnectionDisconnecting;
265 break;
266 case PPP_RUNNING:
267 case PPP_ONHOLD:
268 status = kSCNetworkConnectionConnected;
269 break;
270 case PPP_IDLE:
271 case PPP_STATERESERVED:
272 default:
273 status = kSCNetworkConnectionDisconnected;
274 }
275 return status;
276 }
277
278 /* -------------------------------------------------------------------------------------------
279 ------------------------------------------------------------------------------------------- */
280
281 SCNetworkConnectionRef
282 SCNetworkConnectionCreateWithServiceID (CFAllocatorRef allocator,
283 CFStringRef serviceID,
284 SCNetworkConnectionCallBack callout,
285 SCNetworkConnectionContext *context)
286 {
287 SCNetworkConnectionPrivateRef connectionPrivate;
288
289 if (!isA_CFString(serviceID)) {
290 _SCErrorSet(kSCStatusInvalidArgument);
291 return NULL;
292 }
293
294 connectionPrivate = __SCNetworkConnectionCreatePrivate(allocator, serviceID);
295
296 if (connectionPrivate) {
297 connectionPrivate->rlsFunction = callout;
298 if (context) {
299 bcopy(context, &connectionPrivate->rlsContext, sizeof(SCNetworkConnectionContext));
300 if (context->retain) {
301 connectionPrivate->rlsContext.info = (void *)context->retain(context->info);
302 }
303 }
304 }
305
306 return (SCNetworkConnectionRef)connectionPrivate;
307 }
308
309 /* -------------------------------------------------------------------------------------------
310 ------------------------------------------------------------------------------------------- */
311
312 CFStringRef
313 SCNetworkConnectionCopyServiceID (SCNetworkConnectionRef connection)
314 {
315 if (!isA_SCNetworkConnection(connection)) {
316 _SCErrorSet(kSCStatusInvalidArgument);
317 return NULL;
318 }
319
320 return CFRetain(((SCNetworkConnectionPrivateRef)connection)->serviceID);
321 }
322
323 /* -------------------------------------------------------------------------------------------
324 ------------------------------------------------------------------------------------------- */
325
326 CFDictionaryRef
327 SCNetworkConnectionCopyStatistics (SCNetworkConnectionRef connection)
328 {
329 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
330 int error = kSCStatusFailed;
331 struct ppp_status *stats = 0;
332 CFMutableDictionaryRef dict = 0;
333 CFMutableDictionaryRef statsdict = 0;
334
335 #define ADDNUMBER(d, k, n) \
336 { \
337 CFNumberRef num; \
338 num = CFNumberCreate(NULL, kCFNumberSInt32Type, n); \
339 if (num) { \
340 CFDictionaryAddValue(d, k, num); \
341 CFRelease(num); \
342 } \
343 }
344
345 if (!isA_SCNetworkConnection(connection)) {
346 _SCErrorSet(kSCStatusInvalidArgument);
347 return NULL;
348 }
349
350 /* get status and check connected state */
351 if (PPPStatus(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &stats))
352 goto fail;
353
354 if (__SCNetworkConnectionConvertStatus(stats->status) != kSCNetworkConnectionConnected)
355 goto fail;
356
357 /* create dictionaries */
358 if ((statsdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
359 goto fail;
360
361 if ((dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
362 goto fail;
363
364 /* add statistics */
365 ADDNUMBER(dict, kSCNetworkConnectionBytesIn, &stats->s.run.inBytes);
366 ADDNUMBER(dict, kSCNetworkConnectionBytesOut, &stats->s.run.outBytes);
367 ADDNUMBER(dict, kSCNetworkConnectionPacketsIn, &stats->s.run.inPackets);
368 ADDNUMBER(dict, kSCNetworkConnectionPacketsOut, &stats->s.run.outPackets);
369 ADDNUMBER(dict, kSCNetworkConnectionErrorsIn, &stats->s.run.inErrors);
370 ADDNUMBER(dict, kSCNetworkConnectionErrorsOut, &stats->s.run.outErrors);
371
372 /* add the PPP dictionary to the statistics dictionary */
373 CFDictionaryAddValue(statsdict, kSCEntNetPPP, dict);
374 CFRelease(dict);
375
376 /* done */
377 CFAllocatorDeallocate(NULL, stats);
378 return statsdict;
379
380 fail:
381
382 if (stats)
383 CFAllocatorDeallocate(NULL, stats);
384 if (dict)
385 CFRelease(dict);
386 if (statsdict)
387 CFRelease(statsdict);
388 _SCErrorSet(error);
389 return NULL;
390 }
391
392 /* -------------------------------------------------------------------------------------------
393 ------------------------------------------------------------------------------------------- */
394
395 SCNetworkConnectionStatus
396 SCNetworkConnectionGetStatus (SCNetworkConnectionRef connection)
397 {
398 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
399 struct ppp_status *stats = 0;
400 SCNetworkConnectionStatus status;
401
402 if (!isA_SCNetworkConnection(connection)) {
403 _SCErrorSet(kSCStatusInvalidArgument);
404 return NULL;
405 }
406
407 if (PPPStatus(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &stats))
408 return kSCNetworkConnectionDisconnected; // XXX
409
410 status = __SCNetworkConnectionConvertStatus(stats->status);
411
412 CFAllocatorDeallocate(NULL, stats);
413 return status;
414 }
415
416 /* -------------------------------------------------------------------------------------------
417 ------------------------------------------------------------------------------------------- */
418 CFDictionaryRef
419 SCNetworkConnectionCopyExtendedStatus (SCNetworkConnectionRef connection)
420 {
421 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
422 CFPropertyListRef status = 0;
423 void *data = 0;
424 u_int32_t datalen;
425
426 if (!isA_SCNetworkConnection(connection)) {
427 _SCErrorSet(kSCStatusInvalidArgument);
428 return NULL;
429 }
430
431 if (PPPExtendedStatus(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &data, &datalen))
432 goto fail;
433
434 if (!data
435 || !(status = PPPUnserialize(data, datalen))
436 || !isA_CFDictionary(status))
437 goto fail;
438
439 CFAllocatorDeallocate(NULL, data);
440 return status;
441
442 fail:
443
444 _SCErrorSet(kSCStatusFailed);
445 if (status)
446 CFRelease(status);
447 if (data)
448 CFAllocatorDeallocate(NULL, data);
449 return NULL;
450 }
451
452 /* -------------------------------------------------------------------------------------------
453 ------------------------------------------------------------------------------------------- */
454
455 Boolean
456 SCNetworkConnectionStart (SCNetworkConnectionRef connection,
457 CFDictionaryRef userOptions,
458 Boolean linger)
459 {
460 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
461 CFDataRef dataref = 0;
462 void *data = 0;
463 u_int32_t datalen = 0;
464
465 if (!isA_SCNetworkConnection(connection)) {
466 _SCErrorSet(kSCStatusInvalidArgument);
467 return NULL;
468 }
469
470 if (userOptions && !(dataref = PPPSerialize(userOptions, &data, &datalen)))
471 goto fail;
472
473 if (PPPConnect(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, data, datalen, linger))
474 goto fail;
475
476 if (dataref)
477 CFRelease(dataref);
478
479 /* connection is now started */
480 return TRUE;
481
482 fail:
483
484 if (dataref)
485 CFRelease(dataref);
486 _SCErrorSet(kSCStatusFailed); // XXX
487 return FALSE;
488 }
489
490 /* -------------------------------------------------------------------------------------------
491 ------------------------------------------------------------------------------------------- */
492
493 Boolean
494 SCNetworkConnectionStop (SCNetworkConnectionRef connection,
495 Boolean forceDisconnect)
496 {
497 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
498
499 if (!isA_SCNetworkConnection(connection)) {
500 _SCErrorSet(kSCStatusInvalidArgument);
501 return FALSE;
502 }
503
504 if (PPPDisconnect(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, forceDisconnect)) {
505 _SCErrorSet(kSCStatusFailed);
506 return FALSE;
507 }
508
509 /* connection is now disconnecting */
510 return TRUE;
511 }
512
513 /* -------------------------------------------------------------------------------------------
514 ------------------------------------------------------------------------------------------- */
515
516 Boolean
517 SCNetworkConnectionSuspend (SCNetworkConnectionRef connection)
518 {
519 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
520
521 if (!isA_SCNetworkConnection(connection)) {
522 _SCErrorSet(kSCStatusInvalidArgument);
523 return NULL;
524 }
525
526 if (PPPSuspend(connectionPrivate->controlRef, connectionPrivate->serviceID, 0)) {
527 _SCErrorSet(kSCStatusFailed);
528 return FALSE;
529 }
530
531 /* connection is now suspended */
532 return TRUE;
533 }
534
535 /* -------------------------------------------------------------------------------------------
536 ------------------------------------------------------------------------------------------- */
537
538 Boolean
539 SCNetworkConnectionResume (SCNetworkConnectionRef connection)
540 {
541 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
542
543 if (!isA_SCNetworkConnection(connection)) {
544 _SCErrorSet(kSCStatusInvalidArgument);
545 return NULL;
546 }
547
548 if (PPPResume(connectionPrivate->controlRef, connectionPrivate->serviceID, 0)) {
549 _SCErrorSet(kSCStatusFailed);
550 return FALSE;
551 }
552
553 /* connection is now resume */
554 return TRUE;
555 }
556
557 /* -------------------------------------------------------------------------------------------
558 ------------------------------------------------------------------------------------------- */
559
560 CFDictionaryRef
561 SCNetworkConnectionCopyUserOptions (SCNetworkConnectionRef connection)
562 {
563 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
564 void *data = 0;
565 u_int32_t datalen;
566 CFPropertyListRef userOptions = 0;
567
568 if (!isA_SCNetworkConnection(connection)) {
569 _SCErrorSet(kSCStatusInvalidArgument);
570 return NULL;
571 }
572
573 if (PPPGetConnectData(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &data, &datalen))
574 goto fail;
575
576 // no data were used, return an empty dictionary
577 if (data == 0) {
578 CFDictionaryRef dict;
579
580 dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
581 if (dict == 0)
582 _SCErrorSet(kSCStatusFailed); // XXX
583 return dict;
584 }
585
586 userOptions = PPPUnserialize(data, datalen);
587 if (!isA_CFDictionary(userOptions))
588 goto fail;
589
590 CFAllocatorDeallocate(NULL, data);
591 return userOptions;
592
593 fail:
594
595 _SCErrorSet(kSCStatusFailed);
596 if (userOptions)
597 CFRelease(userOptions);
598 if (data)
599 CFAllocatorDeallocate(NULL, data);
600 return NULL;
601 }
602
603 /* -------------------------------------------------------------------------------------------
604 ------------------------------------------------------------------------------------------- */
605
606 static Boolean
607 __isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
608 {
609 CFIndex i;
610 CFIndex n = CFArrayGetCount(rlList);
611
612 for (i = 0; i < n; i += 3) {
613 if (obj && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
614 continue;
615 }
616 if (runLoop && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
617 continue;
618 }
619 if (runLoopMode && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
620 continue;
621 }
622 return TRUE;
623 }
624
625 return FALSE;
626 }
627
628 /* -------------------------------------------------------------------------------------------
629 ------------------------------------------------------------------------------------------- */
630 static void
631 __schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
632 {
633 CFArrayAppendValue(rlList, obj);
634 CFArrayAppendValue(rlList, runLoop);
635 CFArrayAppendValue(rlList, runLoopMode);
636
637 return;
638 }
639
640 /* -------------------------------------------------------------------------------------------
641 ------------------------------------------------------------------------------------------- */
642 static Boolean
643 __unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all)
644 {
645 CFIndex i = 0;
646 Boolean found = FALSE;
647 CFIndex n = CFArrayGetCount(rlList);
648
649 while (i < n) {
650 if (obj && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
651 i += 3;
652 continue;
653 }
654 if (runLoop && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
655 i += 3;
656 continue;
657 }
658 if (runLoopMode && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
659 i += 3;
660 continue;
661 }
662
663 found = TRUE;
664
665 CFArrayRemoveValueAtIndex(rlList, i + 2);
666 CFArrayRemoveValueAtIndex(rlList, i + 1);
667 CFArrayRemoveValueAtIndex(rlList, i);
668
669 if (!all) {
670 return found;
671 }
672
673 n -= 3;
674 }
675
676 return found;
677 }
678
679 /* -------------------------------------------------------------------------------------------
680 ------------------------------------------------------------------------------------------- */
681
682 static void
683 __SCNetworkConnectionCallBack(CFSocketRef inref,
684 CFSocketCallBackType type,
685 CFDataRef address,
686 const void *data,
687 void *info)
688 {
689 void *context_info;
690 void (*context_release)(const void *);
691 SCNetworkConnectionRef connection = (SCNetworkConnectionRef)info;
692 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
693 SCNetworkConnectionCallBack rlsFunction;
694 SCNetworkConnectionStatus status;
695 int pppstatus;
696 int err;
697
698 err = PPPReadEvent(connectionPrivate->eventRef, &pppstatus);
699 if (err)
700 return;
701
702 rlsFunction = connectionPrivate->rlsFunction;
703 if (connectionPrivate->rlsContext.retain && connectionPrivate->rlsContext.info) {
704 context_info = (void *)connectionPrivate->rlsContext.retain(connectionPrivate->rlsContext.info);
705 context_release = connectionPrivate->rlsContext.release;
706 }
707 else {
708 context_info = connectionPrivate->rlsContext.info;
709 context_release = NULL;
710 }
711
712 status = __SCNetworkConnectionConvertStatus(pppstatus);
713
714 (*rlsFunction)(connection, status, context_info);
715 if (context_release && context_info) {
716 context_release(context_info);
717 }
718 }
719
720 /* -------------------------------------------------------------------------------------------
721 ------------------------------------------------------------------------------------------- */
722
723 Boolean
724 SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection,
725 CFRunLoopRef runLoop,
726 CFStringRef runLoopMode)
727 {
728 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
729 //CFSocketRef ref;
730
731 if (!isA_SCNetworkConnection(connection) || runLoop == NULL || runLoopMode == NULL) {
732 _SCErrorSet(kSCStatusInvalidArgument);
733 return FALSE;
734 }
735
736 if (connectionPrivate->rlsFunction == 0) {
737 _SCErrorSet(kSCStatusInvalidArgument);
738 return FALSE;
739 }
740
741 if (connectionPrivate->rlList
742 && __isScheduled(NULL, runLoop, runLoopMode, connectionPrivate->rlList)) {
743 /* already scheduled */
744 _SCErrorSet(kSCStatusFailed);
745 return FALSE;
746 }
747
748 if (connectionPrivate->eventRef == -1) {
749 CFSocketContext context = { 0, (void*)connection, CFRetain, CFRelease, CFCopyDescription };
750
751 if (PPPInit(&connectionPrivate->eventRef)) {
752 _SCErrorSet(kSCStatusFailed);
753 return FALSE;
754 }
755
756 PPPEnableEvents(connectionPrivate->eventRef, connectionPrivate->serviceID, 0, 1);
757
758 connectionPrivate->eventRefCF = CFSocketCreateWithNative(NULL, connectionPrivate->eventRef,
759 kCFSocketReadCallBack, __SCNetworkConnectionCallBack, &context);
760 connectionPrivate->rls = CFSocketCreateRunLoopSource(NULL, connectionPrivate->eventRefCF, 0);
761 connectionPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
762
763 //CFRelease(ref);
764 }
765
766 CFRunLoopAddSource(runLoop, connectionPrivate->rls, runLoopMode);
767 __schedule(connectionPrivate, runLoop, runLoopMode, connectionPrivate->rlList);
768
769 return TRUE;
770 }
771
772 /* -------------------------------------------------------------------------------------------
773 ------------------------------------------------------------------------------------------- */
774
775 Boolean
776 SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection,
777 CFRunLoopRef runLoop,
778 CFStringRef runLoopMode)
779 {
780 SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
781
782 if (!isA_SCNetworkConnection(connection) || runLoop == NULL || runLoopMode == NULL) {
783 _SCErrorSet(kSCStatusInvalidArgument);
784 return FALSE;
785 }
786
787 if (connectionPrivate->rlList == NULL
788 || !__unschedule(connectionPrivate, runLoop, runLoopMode, connectionPrivate->rlList, FALSE)) {
789 /* if not currently scheduled */
790 _SCErrorSet(kSCStatusFailed);
791 return FALSE;
792 }
793
794 CFRunLoopRemoveSource(runLoop, connectionPrivate->rls, runLoopMode);
795
796 if (CFArrayGetCount(connectionPrivate->rlList) == 0) {
797 CFRelease(connectionPrivate->rls);
798 connectionPrivate->rls = NULL;
799 CFRelease(connectionPrivate->rlList);
800 connectionPrivate->rlList = NULL;
801 //PPPDispose(connectionPrivate->eventRef);
802 CFSocketInvalidate(connectionPrivate->eventRefCF);
803 CFRelease(connectionPrivate->eventRefCF);
804 connectionPrivate->eventRefCF = 0;
805 connectionPrivate->eventRef = -1;
806 }
807
808 return TRUE;
809 }
810
811
812 //************************* USER LEVEL DIAL API **********************************
813
814
815 #define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
816 #define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
817
818 #define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
819 #define k_Last_Service_Id_Key CFSTR("ServiceID")
820 #define k_Unique_Id_Key CFSTR("UniqueIdentifier")
821
822
823 /* Private Prototypes */
824 static Boolean SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session, CFStringRef *serviceID);
825 static Boolean SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session, CFStringRef *serviceID);
826 static Boolean SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray, CFDictionaryRef *userOptions);
827 static Boolean SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session, CFStringRef serviceID);
828 static void addPasswordFromKeychain(CFDictionaryRef *userOptions);
829 static CFArrayRef copyKeychainEnumerator(CFStringRef uniqueIdentifier);
830
831 Boolean
832 SCNetworkConnectionCopyUserPreferences (CFDictionaryRef selectionOptions,
833 CFStringRef *serviceID,
834 CFDictionaryRef *userOptions)
835 {
836 SCDynamicStoreRef session = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkConnection"), NULL, NULL);
837 Boolean success = FALSE;
838
839 // NOTE: we are currently ignoring selectionOptions
840
841 if (session != NULL) {
842 // (1) Figure out which service ID we care about, allocate it into passed "serviceID"
843 success = SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session, serviceID);
844
845 if (success && (*serviceID != NULL)) {
846 // (2) Get the list of user data for this service ID
847 CFPropertyListRef userServices = CFPreferencesCopyValue(*serviceID,
848 k_NetworkConnect_Pref_File,
849 kCFPreferencesCurrentUser,
850 kCFPreferencesCurrentHost);
851
852 // (3) We are expecting an array if the user has defined records for this service ID or NULL if the user hasn't
853 if (userServices != NULL) {
854 if (isA_CFArray(userServices)) {
855 // (4) Get the default set of user options for this service
856 success = SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(
857 (CFArrayRef)userServices,
858 userOptions);
859 if(success && userOptions != NULL)
860 {
861 addPasswordFromKeychain(userOptions);
862 }
863 } else {
864 fprintf(stderr, "Error, userServices are not of type CFArray!\n");
865 }
866
867 CFRelease(userServices); // this is OK because SCNetworkConnectionPrivateISExpectedCFType() checks for NULL
868 }
869 }
870
871 CFRelease(session);
872 } else {
873 fprintf(stderr, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
874 }
875
876 return success;
877 }
878
879 //*******************************************************************************************
880 // SCNetworkConnectionPrivateCopyDefaultServiceIDForDial
881 // ----------------------------------------------------
882 // Try to find the service id to connect
883 // (1) Start by looking at the last service used in Internet Connect
884 // (2) If Internet Connect has not been used, find the PPP service with the highest ordering
885 //********************************************************************************************
886 static Boolean
887 SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session, CFStringRef *serviceID)
888 {
889 Boolean foundService = FALSE;
890 CFPropertyListRef lastServiceSelectedInIC = NULL;
891
892 // NULL out the pointer
893 *serviceID = NULL;
894
895 // read out the last service from the Internet Connect preference file
896 lastServiceSelectedInIC = CFPreferencesCopyValue(k_Last_Service_Id_Key,
897 k_InterentConnect_Pref_File,
898 kCFPreferencesCurrentUser,
899 kCFPreferencesAnyHost);
900
901 // we found the service the user last had open in IC
902 if (lastServiceSelectedInIC != NULL) {
903 // make sure its a PPP service
904 if (SCNetworkConnectionPrivateIsPPPService(session, lastServiceSelectedInIC)) {
905 // make sure the service that we found is valid
906 CFDictionaryRef dict;
907 CFStringRef key;
908
909 key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
910 kSCDynamicStoreDomainSetup,
911 lastServiceSelectedInIC,
912 kSCEntNetInterface);
913 dict = SCDynamicStoreCopyValue(session, key);
914 CFRelease(key);
915 if (dict) {
916 *serviceID = CFRetain(lastServiceSelectedInIC);
917 foundService = TRUE;
918 CFRelease(dict);
919 }
920 }
921 CFRelease(lastServiceSelectedInIC);
922 }
923
924 if (!foundService) {
925 foundService = SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session, serviceID);
926 }
927
928 return foundService;
929 }
930
931 //********************************************************************************
932 // SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore
933 // -------------------------------------------------------
934 // Find the highest ordered PPP service in the dynamic store
935 //********************************************************************************
936 static Boolean
937 SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session, CFStringRef *serviceID)
938 {
939 Boolean success = FALSE;
940 CFStringRef key = NULL;
941 CFDictionaryRef dict = NULL;
942 CFArrayRef serviceIDs = NULL;
943
944 *serviceID = NULL;
945
946 do {
947 CFIndex count;
948 CFIndex i;
949
950 key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, kSCEntNetIPv4);
951 if (key == NULL) {
952 fprintf(stderr, "Error, Setup Key == NULL!\n");
953 break;
954 }
955
956 dict = SCDynamicStoreCopyValue(session, key);
957 if (dict == NULL) {
958 fprintf(stderr, "Error, Dictionary for setup key == NULL!\n");
959 break;
960 }
961
962 serviceIDs = CFDictionaryGetValue(dict, kSCPropNetServiceOrder); // array of service id's
963 if (isA_CFArray(serviceIDs) == NULL) {
964 if (serviceIDs == NULL)
965 fprintf(stderr, "Error, Array of service IDs == NULL!\n");
966 else
967 fprintf(stderr, "Error, serviceIds are not of type CFArray!\n");
968 break;
969 }
970
971 count = CFArrayGetCount(serviceIDs);
972 for (i = 0; i < count; i++) {
973 CFStringRef service = CFArrayGetValueAtIndex(serviceIDs, i);
974
975 if (SCNetworkConnectionPrivateIsPPPService(session, service)) {
976 *serviceID = CFRetain(service);
977 success = TRUE;
978 break;
979 }
980 }
981 } while (FALSE);
982
983 if (key != NULL)
984 CFRelease(key);
985
986 if (dict != NULL)
987 CFRelease(dict);
988
989 return success;
990 }
991
992 //********************************************************************************
993 // SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray
994 // ---------------------------------------------------------
995 // Copy over user preferences for a particular service if they exist
996 //********************************************************************************
997 static Boolean
998 SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray, CFDictionaryRef *userOptions)
999 {
1000 CFIndex count = CFArrayGetCount(userOptionsArray);
1001 int i;
1002
1003 *userOptions = NULL;
1004
1005 for (i = 0; i < count; i++) {
1006 // (1) Find the dictionary
1007 CFPropertyListRef propertyList = CFArrayGetValueAtIndex(userOptionsArray, i);
1008
1009 if (isA_CFDictionary(propertyList) != NULL) {
1010 // See if there's a value for dial on demand
1011 CFPropertyListRef value = CFDictionaryGetValue((CFDictionaryRef)propertyList,
1012 k_Dial_Default_Key);
1013 if (isA_CFBoolean(value) != NULL) {
1014 if (CFBooleanGetValue(value)) {
1015 // we found the default user options
1016 *userOptions = CFDictionaryCreateCopy(NULL,
1017 (CFDictionaryRef)propertyList);
1018 break;
1019 }
1020 }
1021 }
1022 }
1023
1024 return TRUE;
1025 }
1026
1027 //********************************************************************************
1028 // SCNetworkConnectionPrivateIsPPPService
1029 // --------------------------------------
1030 // Check and see if the service is a PPP service
1031 //********************************************************************************
1032 static Boolean
1033 SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session, CFStringRef serviceID)
1034 {
1035 CFStringRef entityKey;
1036 Boolean isPPPService = FALSE;
1037 Boolean isModemOrPPPoE = FALSE;
1038
1039 entityKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
1040 kSCDynamicStoreDomainSetup,
1041 serviceID,
1042 kSCEntNetInterface);
1043 if (entityKey != NULL) {
1044 CFDictionaryRef serviceDict;
1045
1046 serviceDict = SCDynamicStoreCopyValue(session, entityKey);
1047 if (serviceDict != NULL) {
1048 if (isA_CFDictionary(serviceDict)) {
1049 CFStringRef type;
1050 CFStringRef subtype;
1051
1052 type = CFDictionaryGetValue(serviceDict, kSCPropNetInterfaceType);
1053 if (isA_CFString(type)) {
1054 isPPPService = CFEqual(type, kSCValNetInterfaceTypePPP);
1055 }
1056
1057 subtype = CFDictionaryGetValue(serviceDict, kSCPropNetInterfaceSubType);
1058 if (isA_CFString(subtype)) {
1059 isModemOrPPPoE = (CFEqual(subtype, kSCValNetInterfaceSubTypePPPSerial) ||
1060 CFEqual(subtype, kSCValNetInterfaceSubTypePPPoE));
1061 }
1062 }
1063 CFRelease(serviceDict);
1064 }
1065 CFRelease(entityKey);
1066 }
1067
1068 return (isPPPService && isModemOrPPPoE);
1069 }
1070
1071 //********************************************************************************
1072 // addPasswordFromKeychain
1073 // --------------------------------------
1074 // Get the password out of the keychain and add it to the PPP dictionary
1075 //********************************************************************************
1076 static void
1077 addPasswordFromKeychain(CFDictionaryRef *userOptions)
1078 {
1079 CFArrayRef enumerator;
1080 CFIndex n;
1081 CFDictionaryRef oldDict;
1082 CFPropertyListRef uniqueID = NULL;
1083
1084 oldDict = *userOptions;
1085 if(oldDict == NULL) {
1086 return; // if no userOptions
1087 }
1088
1089 uniqueID = CFDictionaryGetValue(oldDict, k_Unique_Id_Key);
1090 if(!isA_CFString(uniqueID)) {
1091 return; // if no unique ID
1092 }
1093
1094 enumerator = copyKeychainEnumerator(uniqueID);
1095 if(enumerator == NULL) {
1096 return; // if no keychain enumerator
1097 }
1098
1099
1100 n = CFArrayGetCount(enumerator);
1101 if (n > 0) {
1102 void *data = NULL;
1103 UInt32 dataLen = 0;
1104 SecKeychainItemRef itemRef;
1105 OSStatus result;
1106
1107 itemRef = (SecKeychainItemRef)CFArrayGetValueAtIndex(enumerator, 0);
1108 result = SecKeychainItemCopyContent(itemRef, // itemRef
1109 NULL, // itemClass
1110 NULL, // attrList
1111 &dataLen, // length
1112 (void *)&data); // outData
1113 if(result == noErr && data != NULL && dataLen > 0) {
1114 CFStringRef pass;
1115
1116 pass = CFStringCreateWithBytes(NULL, data, dataLen, kCFStringEncodingUTF8, TRUE);
1117 if (pass) {
1118 CFMutableDictionaryRef newDict;
1119 CFMutableDictionaryRef newPPP;
1120 CFDictionaryRef pppDict;
1121
1122 newDict = CFDictionaryCreateMutableCopy(NULL, 0, oldDict);
1123 pppDict = CFDictionaryGetValue(newDict, kSCEntNetPPP);
1124 if (isA_CFDictionary(pppDict)) {
1125 newPPP = CFDictionaryCreateMutableCopy(NULL, 0, pppDict);
1126 } else {
1127 newPPP = CFDictionaryCreateMutable(NULL,
1128 0,
1129 &kCFTypeDictionaryKeyCallBacks,
1130 &kCFTypeDictionaryValueCallBacks);
1131 }
1132
1133 // set the PPP password
1134 CFDictionarySetValue(newPPP, kSCPropNetPPPAuthPassword, pass);
1135 CFRelease(pass);
1136
1137 // update the PPP entity
1138 CFDictionarySetValue(newDict, kSCEntNetPPP, newPPP);
1139 CFRelease(newPPP);
1140
1141 // update the userOptions dictionary
1142 CFRelease(oldDict);
1143 *userOptions = CFDictionaryCreateCopy(NULL, newDict);
1144 CFRelease(newDict);
1145 }
1146 }
1147 }
1148
1149 CFRelease(enumerator);
1150 return;
1151 }
1152
1153 //********************************************************************************
1154 // copyKeychainEnumerator
1155 // --------------------------------------
1156 // Gather Keychain Enumerator
1157 //********************************************************************************
1158 static CFArrayRef
1159 copyKeychainEnumerator(CFStringRef uniqueIdentifier)
1160 {
1161 char *buf = NULL;
1162 CFMutableArrayRef itemArray = NULL;
1163 OSStatus result;
1164 SecKeychainSearchRef search = NULL;
1165
1166 buf = _SC_cfstring_to_cstring(uniqueIdentifier, NULL, 0, kCFStringEncodingUTF8);
1167 if (buf != NULL) {
1168 // search for unique identifier in "svce" attribute
1169 SecKeychainAttribute attributes[] = {{ kSecServiceItemAttr,
1170 CFStringGetLength(uniqueIdentifier),
1171 (void *)buf
1172 }};
1173
1174 SecKeychainAttributeList attrList = { sizeof(attributes) / sizeof(*attributes),
1175 attributes };
1176
1177 result = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attrList, &search);
1178 if (result == noErr) {
1179 itemArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1180
1181 while (result == noErr) {
1182 SecKeychainItemRef itemFound = NULL;
1183
1184 result = SecKeychainSearchCopyNext(search, &itemFound);
1185 if (result != noErr) {
1186 break;
1187 }
1188
1189 if (itemFound) {
1190 CFArrayAppendValue(itemArray, itemFound);
1191 CFRelease(itemFound);
1192 }
1193 }
1194 }
1195 }
1196
1197 if (search) CFRelease(search);
1198 if (buf) CFAllocatorDeallocate(NULL, buf);
1199
1200 return itemArray;
1201 }