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