SCNetworkConnection.c [plain text]
#include <CoreFoundation/CoreFoundation.h>
#include <CoreFoundation/CFRuntime.h>
#include <Security/Security.h>
#include "dy_framework.h"
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include <SystemConfiguration/SCValidation.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include "ppp.h"
typedef struct {
CFRuntimeBase cfBase;
CFStringRef serviceID;
int eventRef;
CFSocketRef eventRefCF;
int controlRef;
CFRunLoopSourceRef rls;
SCNetworkConnectionCallBack rlsFunction;
SCNetworkConnectionContext rlsContext;
CFMutableArrayRef rlList;
} SCNetworkConnectionPrivate, *SCNetworkConnectionPrivateRef;
static __inline__ CFTypeRef
isA_SCNetworkConnection(CFTypeRef obj)
{
return (isA_CFType(obj, SCNetworkConnectionGetTypeID()));
}
static CFStringRef
__SCNetworkConnectionCopyDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)cf;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<SCNetworkConnection, %p [%p]> {\n"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR(" serviceID = %@ \n"), connectionPrivate->serviceID);
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void
__SCNetworkConnectionDeallocate(CFTypeRef cf)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)cf;
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkConnectionDeallocate:"));
if (connectionPrivate->eventRef != -1) {
while (CFArrayGetCount(connectionPrivate->rlList)) {
CFRunLoopRef runLoop;
CFStringRef runLoopMode;
runLoop = (CFRunLoopRef)CFArrayGetValueAtIndex(connectionPrivate->rlList, 1);
runLoopMode = CFArrayGetValueAtIndex(connectionPrivate->rlList, 2);
CFRunLoopRemoveSource(runLoop, connectionPrivate->rls, runLoopMode);
CFArrayRemoveValueAtIndex(connectionPrivate->rlList, 2);
CFArrayRemoveValueAtIndex(connectionPrivate->rlList, 1);
CFArrayRemoveValueAtIndex(connectionPrivate->rlList, 0);
}
CFRelease(connectionPrivate->rls);
CFRelease(connectionPrivate->rlList);
CFSocketInvalidate(connectionPrivate->eventRefCF);
CFRelease(connectionPrivate->eventRefCF);
}
if (connectionPrivate->controlRef != -1)
PPPDispose(connectionPrivate->controlRef);
if (connectionPrivate->rlsContext.release)
connectionPrivate->rlsContext.release(connectionPrivate->rlsContext.info);
if (connectionPrivate->serviceID)
CFRelease(connectionPrivate->serviceID);
return;
}
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static CFTypeID __kSCNetworkConnectionTypeID = _kCFRuntimeNotATypeID;
static const CFRuntimeClass __SCNetworkConnectionClass = {
0, "SCNetworkConnection", NULL, NULL, __SCNetworkConnectionDeallocate, NULL, NULL, NULL, __SCNetworkConnectionCopyDescription };
static void
__SCNetworkConnectionInitialize(void)
{
__kSCNetworkConnectionTypeID = _CFRuntimeRegisterClass(&__SCNetworkConnectionClass);
return;
}
static SCNetworkConnectionPrivateRef
__SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator, CFStringRef serviceID)
{
SCNetworkConnectionPrivateRef connectionPrivate = 0;
uint32_t size;
struct ppp_status *stats = 0;
int error = kSCStatusFailed;
pthread_once(&initialized, __SCNetworkConnectionInitialize);
SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCNetworkConnectionCreatePrivate:"));
size = sizeof(SCNetworkConnectionPrivate) - sizeof(CFRuntimeBase);
connectionPrivate = (SCNetworkConnectionPrivateRef)_CFRuntimeCreateInstance(allocator, __kSCNetworkConnectionTypeID,size, NULL);
if (connectionPrivate == 0)
goto fail;
bzero(((u_char*)connectionPrivate)+sizeof(CFRuntimeBase), size);
connectionPrivate->serviceID = CFStringCreateCopy(NULL, serviceID);
connectionPrivate->controlRef = -1;
connectionPrivate->eventRef = -1;
if (PPPInit(&connectionPrivate->controlRef))
goto fail;
if (PPPStatus(connectionPrivate->controlRef, serviceID, 0, &stats)) {
error = kSCStatusInvalidArgument; goto fail;
}
CFAllocatorDeallocate(NULL, stats);
stats = 0;
return connectionPrivate;
fail:
if (connectionPrivate)
CFRelease(connectionPrivate);
if (stats)
CFAllocatorDeallocate(NULL, stats);
_SCErrorSet(error);
return NULL;
}
CFTypeID
SCNetworkConnectionGetTypeID (void) {
pthread_once(&initialized, __SCNetworkConnectionInitialize);
return __kSCNetworkConnectionTypeID;
}
static SCNetworkConnectionStatus
__SCNetworkConnectionConvertStatus (int state)
{
SCNetworkConnectionStatus status = kSCNetworkConnectionDisconnected;
switch (state) {
case PPP_INITIALIZE:
case PPP_CONNECTLINK:
case PPP_ESTABLISH:
case PPP_AUTHENTICATE:
case PPP_CALLBACK:
case PPP_NETWORK:
case PPP_WAITONBUSY:
status = kSCNetworkConnectionConnecting;
break;
case PPP_TERMINATE:
case PPP_DISCONNECTLINK:
case PPP_HOLDOFF:
status = kSCNetworkConnectionDisconnecting;
break;
case PPP_RUNNING:
case PPP_ONHOLD:
status = kSCNetworkConnectionConnected;
break;
case PPP_IDLE:
case PPP_STATERESERVED:
default:
status = kSCNetworkConnectionDisconnected;
}
return status;
}
SCNetworkConnectionRef
SCNetworkConnectionCreateWithServiceID (CFAllocatorRef allocator,
CFStringRef serviceID,
SCNetworkConnectionCallBack callout,
SCNetworkConnectionContext *context)
{
SCNetworkConnectionPrivateRef connectionPrivate;
if (!isA_CFString(serviceID)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
connectionPrivate = __SCNetworkConnectionCreatePrivate(allocator, serviceID);
if (connectionPrivate) {
connectionPrivate->rlsFunction = callout;
if (context) {
bcopy(context, &connectionPrivate->rlsContext, sizeof(SCNetworkConnectionContext));
if (context->retain) {
connectionPrivate->rlsContext.info = (void *)context->retain(context->info);
}
}
}
return (SCNetworkConnectionRef)connectionPrivate;
}
CFStringRef
SCNetworkConnectionCopyServiceID (SCNetworkConnectionRef connection)
{
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
return CFRetain(((SCNetworkConnectionPrivateRef)connection)->serviceID);
}
CFDictionaryRef
SCNetworkConnectionCopyStatistics (SCNetworkConnectionRef connection)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
int error = kSCStatusFailed;
struct ppp_status *stats = 0;
CFMutableDictionaryRef dict = 0;
CFMutableDictionaryRef statsdict = 0;
#define ADDNUMBER(d, k, n) \
{ \
CFNumberRef num; \
num = CFNumberCreate(NULL, kCFNumberSInt32Type, n); \
if (num) { \
CFDictionaryAddValue(d, k, num); \
CFRelease(num); \
} \
}
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (PPPStatus(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &stats))
goto fail;
if (__SCNetworkConnectionConvertStatus(stats->status) != kSCNetworkConnectionConnected)
goto fail;
if ((statsdict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
goto fail;
if ((dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == 0)
goto fail;
ADDNUMBER(dict, kSCNetworkConnectionBytesIn, &stats->s.run.inBytes);
ADDNUMBER(dict, kSCNetworkConnectionBytesOut, &stats->s.run.outBytes);
ADDNUMBER(dict, kSCNetworkConnectionPacketsIn, &stats->s.run.inPackets);
ADDNUMBER(dict, kSCNetworkConnectionPacketsOut, &stats->s.run.outPackets);
ADDNUMBER(dict, kSCNetworkConnectionErrorsIn, &stats->s.run.inErrors);
ADDNUMBER(dict, kSCNetworkConnectionErrorsOut, &stats->s.run.outErrors);
CFDictionaryAddValue(statsdict, kSCEntNetPPP, dict);
CFRelease(dict);
CFAllocatorDeallocate(NULL, stats);
return statsdict;
fail:
if (stats)
CFAllocatorDeallocate(NULL, stats);
if (dict)
CFRelease(dict);
if (statsdict)
CFRelease(statsdict);
_SCErrorSet(error);
return NULL;
}
SCNetworkConnectionStatus
SCNetworkConnectionGetStatus (SCNetworkConnectionRef connection)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
struct ppp_status *stats = 0;
SCNetworkConnectionStatus status;
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (PPPStatus(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &stats))
return kSCNetworkConnectionDisconnected;
status = __SCNetworkConnectionConvertStatus(stats->status);
CFAllocatorDeallocate(NULL, stats);
return status;
}
CFDictionaryRef
SCNetworkConnectionCopyExtendedStatus (SCNetworkConnectionRef connection)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
CFPropertyListRef status = 0;
void *data = 0;
u_int32_t datalen;
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (PPPExtendedStatus(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &data, &datalen))
goto fail;
if (!data
|| !(status = PPPUnserialize(data, datalen))
|| !isA_CFDictionary(status))
goto fail;
CFAllocatorDeallocate(NULL, data);
return status;
fail:
_SCErrorSet(kSCStatusFailed);
if (status)
CFRelease(status);
if (data)
CFAllocatorDeallocate(NULL, data);
return NULL;
}
Boolean
SCNetworkConnectionStart (SCNetworkConnectionRef connection,
CFDictionaryRef userOptions,
Boolean linger)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
CFDataRef dataref = 0;
void *data = 0;
u_int32_t datalen = 0;
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (userOptions && !(dataref = PPPSerialize(userOptions, &data, &datalen)))
goto fail;
if (PPPConnect(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, data, datalen, linger))
goto fail;
if (dataref)
CFRelease(dataref);
return TRUE;
fail:
if (dataref)
CFRelease(dataref);
_SCErrorSet(kSCStatusFailed); return FALSE;
}
Boolean
SCNetworkConnectionStop (SCNetworkConnectionRef connection,
Boolean forceDisconnect)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (PPPDisconnect(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, forceDisconnect)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
return TRUE;
}
Boolean
SCNetworkConnectionSuspend (SCNetworkConnectionRef connection)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (PPPSuspend(connectionPrivate->controlRef, connectionPrivate->serviceID, 0)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
return TRUE;
}
Boolean
SCNetworkConnectionResume (SCNetworkConnectionRef connection)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (PPPResume(connectionPrivate->controlRef, connectionPrivate->serviceID, 0)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
return TRUE;
}
CFDictionaryRef
SCNetworkConnectionCopyUserOptions (SCNetworkConnectionRef connection)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
void *data = 0;
u_int32_t datalen;
CFPropertyListRef userOptions = 0;
if (!isA_SCNetworkConnection(connection)) {
_SCErrorSet(kSCStatusInvalidArgument);
return NULL;
}
if (PPPGetConnectData(connectionPrivate->controlRef, connectionPrivate->serviceID, 0, &data, &datalen))
goto fail;
if (data == 0) {
CFDictionaryRef dict;
dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (dict == 0)
_SCErrorSet(kSCStatusFailed); return dict;
}
userOptions = PPPUnserialize(data, datalen);
if (!isA_CFDictionary(userOptions))
goto fail;
CFAllocatorDeallocate(NULL, data);
return userOptions;
fail:
_SCErrorSet(kSCStatusFailed);
if (userOptions)
CFRelease(userOptions);
if (data)
CFAllocatorDeallocate(NULL, data);
return NULL;
}
static Boolean
__isScheduled(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
{
CFIndex i;
CFIndex n = CFArrayGetCount(rlList);
for (i = 0; i < n; i += 3) {
if (obj && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
continue;
}
if (runLoop && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
continue;
}
if (runLoopMode && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
continue;
}
return TRUE;
}
return FALSE;
}
static void
__schedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList)
{
CFArrayAppendValue(rlList, obj);
CFArrayAppendValue(rlList, runLoop);
CFArrayAppendValue(rlList, runLoopMode);
return;
}
static Boolean
__unschedule(CFTypeRef obj, CFRunLoopRef runLoop, CFStringRef runLoopMode, CFMutableArrayRef rlList, Boolean all)
{
CFIndex i = 0;
Boolean found = FALSE;
CFIndex n = CFArrayGetCount(rlList);
while (i < n) {
if (obj && !CFEqual(obj, CFArrayGetValueAtIndex(rlList, i))) {
i += 3;
continue;
}
if (runLoop && !CFEqual(runLoop, CFArrayGetValueAtIndex(rlList, i+1))) {
i += 3;
continue;
}
if (runLoopMode && !CFEqual(runLoopMode, CFArrayGetValueAtIndex(rlList, i+2))) {
i += 3;
continue;
}
found = TRUE;
CFArrayRemoveValueAtIndex(rlList, i + 2);
CFArrayRemoveValueAtIndex(rlList, i + 1);
CFArrayRemoveValueAtIndex(rlList, i);
if (!all) {
return found;
}
n -= 3;
}
return found;
}
static void
__SCNetworkConnectionCallBack(CFSocketRef inref,
CFSocketCallBackType type,
CFDataRef address,
const void *data,
void *info)
{
void *context_info;
void (*context_release)(const void *);
SCNetworkConnectionRef connection = (SCNetworkConnectionRef)info;
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
SCNetworkConnectionCallBack rlsFunction;
SCNetworkConnectionStatus status;
int pppstatus;
int err;
err = PPPReadEvent(connectionPrivate->eventRef, &pppstatus);
if (err)
return;
rlsFunction = connectionPrivate->rlsFunction;
if (connectionPrivate->rlsContext.retain && connectionPrivate->rlsContext.info) {
context_info = (void *)connectionPrivate->rlsContext.retain(connectionPrivate->rlsContext.info);
context_release = connectionPrivate->rlsContext.release;
}
else {
context_info = connectionPrivate->rlsContext.info;
context_release = NULL;
}
status = __SCNetworkConnectionConvertStatus(pppstatus);
(*rlsFunction)(connection, status, context_info);
if (context_release && context_info) {
context_release(context_info);
}
}
Boolean
SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection,
CFRunLoopRef runLoop,
CFStringRef runLoopMode)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
if (!isA_SCNetworkConnection(connection) || runLoop == NULL || runLoopMode == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (connectionPrivate->rlsFunction == 0) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (connectionPrivate->rlList
&& __isScheduled(NULL, runLoop, runLoopMode, connectionPrivate->rlList)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
if (connectionPrivate->eventRef == -1) {
CFSocketContext context = { 0, (void*)connection, CFRetain, CFRelease, CFCopyDescription };
if (PPPInit(&connectionPrivate->eventRef)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
PPPEnableEvents(connectionPrivate->eventRef, connectionPrivate->serviceID, 0, 1);
connectionPrivate->eventRefCF = CFSocketCreateWithNative(NULL, connectionPrivate->eventRef,
kCFSocketReadCallBack, __SCNetworkConnectionCallBack, &context);
connectionPrivate->rls = CFSocketCreateRunLoopSource(NULL, connectionPrivate->eventRefCF, 0);
connectionPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
CFRunLoopAddSource(runLoop, connectionPrivate->rls, runLoopMode);
__schedule(connectionPrivate, runLoop, runLoopMode, connectionPrivate->rlList);
return TRUE;
}
Boolean
SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection,
CFRunLoopRef runLoop,
CFStringRef runLoopMode)
{
SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection;
if (!isA_SCNetworkConnection(connection) || runLoop == NULL || runLoopMode == NULL) {
_SCErrorSet(kSCStatusInvalidArgument);
return FALSE;
}
if (connectionPrivate->rlList == NULL
|| !__unschedule(connectionPrivate, runLoop, runLoopMode, connectionPrivate->rlList, FALSE)) {
_SCErrorSet(kSCStatusFailed);
return FALSE;
}
CFRunLoopRemoveSource(runLoop, connectionPrivate->rls, runLoopMode);
if (CFArrayGetCount(connectionPrivate->rlList) == 0) {
CFRelease(connectionPrivate->rls);
connectionPrivate->rls = NULL;
CFRelease(connectionPrivate->rlList);
connectionPrivate->rlList = NULL;
CFSocketInvalidate(connectionPrivate->eventRefCF);
CFRelease(connectionPrivate->eventRefCF);
connectionPrivate->eventRefCF = 0;
connectionPrivate->eventRef = -1;
}
return TRUE;
}
#define k_NetworkConnect_Pref_File CFSTR("com.apple.networkConnect")
#define k_InterentConnect_Pref_File CFSTR("com.apple.internetconnect")
#define k_Dial_Default_Key CFSTR("ConnectByDefault") // needs to go into SC
#define k_Last_Service_Id_Key CFSTR("ServiceID")
#define k_Unique_Id_Key CFSTR("UniqueIdentifier")
static Boolean SCNetworkConnectionPrivateCopyDefaultServiceIDForDial (SCDynamicStoreRef session, CFStringRef *serviceID);
static Boolean SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore (SCDynamicStoreRef session, CFStringRef *serviceID);
static Boolean SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray, CFDictionaryRef *userOptions);
static Boolean SCNetworkConnectionPrivateIsPPPService (SCDynamicStoreRef session, CFStringRef serviceID);
static void addPasswordFromKeychain(CFDictionaryRef *userOptions);
static CFArrayRef copyKeychainEnumerator(CFStringRef uniqueIdentifier);
Boolean
SCNetworkConnectionCopyUserPreferences (CFDictionaryRef selectionOptions,
CFStringRef *serviceID,
CFDictionaryRef *userOptions)
{
SCDynamicStoreRef session = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkConnection"), NULL, NULL);
Boolean success = FALSE;
if (session != NULL) {
success = SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(session, serviceID);
if (success && (*serviceID != NULL)) {
CFPropertyListRef userServices = CFPreferencesCopyValue(*serviceID,
k_NetworkConnect_Pref_File,
kCFPreferencesCurrentUser,
kCFPreferencesCurrentHost);
if (userServices != NULL) {
if (isA_CFArray(userServices)) {
success = SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(
(CFArrayRef)userServices,
userOptions);
if(success && userOptions != NULL)
{
addPasswordFromKeychain(userOptions);
}
} else {
fprintf(stderr, "Error, userServices are not of type CFArray!\n");
}
CFRelease(userServices); }
}
CFRelease(session);
} else {
fprintf(stderr, "Error, SCNetworkConnectionCopyUserPreferences, SCDynamicStoreCreate() returned NULL!\n");
}
return success;
}
static Boolean
SCNetworkConnectionPrivateCopyDefaultServiceIDForDial(SCDynamicStoreRef session, CFStringRef *serviceID)
{
Boolean foundService = FALSE;
CFPropertyListRef lastServiceSelectedInIC = NULL;
*serviceID = NULL;
lastServiceSelectedInIC = CFPreferencesCopyValue(k_Last_Service_Id_Key,
k_InterentConnect_Pref_File,
kCFPreferencesCurrentUser,
kCFPreferencesAnyHost);
if (lastServiceSelectedInIC != NULL) {
if (SCNetworkConnectionPrivateIsPPPService(session, lastServiceSelectedInIC)) {
CFDictionaryRef dict;
CFStringRef key;
key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
lastServiceSelectedInIC,
kSCEntNetInterface);
dict = SCDynamicStoreCopyValue(session, key);
CFRelease(key);
if (dict) {
*serviceID = CFRetain(lastServiceSelectedInIC);
foundService = TRUE;
CFRelease(dict);
}
}
CFRelease(lastServiceSelectedInIC);
}
if (!foundService) {
foundService = SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(session, serviceID);
}
return foundService;
}
static Boolean
SCNetworkConnectionPrivateGetPPPServiceFromDynamicStore(SCDynamicStoreRef session, CFStringRef *serviceID)
{
Boolean success = FALSE;
CFStringRef key = NULL;
CFDictionaryRef dict = NULL;
CFArrayRef serviceIDs = NULL;
*serviceID = NULL;
do {
CFIndex count;
CFIndex i;
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, kSCEntNetIPv4);
if (key == NULL) {
fprintf(stderr, "Error, Setup Key == NULL!\n");
break;
}
dict = SCDynamicStoreCopyValue(session, key);
if (dict == NULL) {
fprintf(stderr, "Error, Dictionary for setup key == NULL!\n");
break;
}
serviceIDs = CFDictionaryGetValue(dict, kSCPropNetServiceOrder); if (isA_CFArray(serviceIDs) == NULL) {
if (serviceIDs == NULL)
fprintf(stderr, "Error, Array of service IDs == NULL!\n");
else
fprintf(stderr, "Error, serviceIds are not of type CFArray!\n");
break;
}
count = CFArrayGetCount(serviceIDs);
for (i = 0; i < count; i++) {
CFStringRef service = CFArrayGetValueAtIndex(serviceIDs, i);
if (SCNetworkConnectionPrivateIsPPPService(session, service)) {
*serviceID = CFRetain(service);
success = TRUE;
break;
}
}
} while (FALSE);
if (key != NULL)
CFRelease(key);
if (dict != NULL)
CFRelease(dict);
return success;
}
static Boolean
SCNetworkConnectionPrivateCopyDefaultUserOptionsFromArray(CFArrayRef userOptionsArray, CFDictionaryRef *userOptions)
{
CFIndex count = CFArrayGetCount(userOptionsArray);
int i;
*userOptions = NULL;
for (i = 0; i < count; i++) {
CFPropertyListRef propertyList = CFArrayGetValueAtIndex(userOptionsArray, i);
if (isA_CFDictionary(propertyList) != NULL) {
CFPropertyListRef value = CFDictionaryGetValue((CFDictionaryRef)propertyList,
k_Dial_Default_Key);
if (isA_CFBoolean(value) != NULL) {
if (CFBooleanGetValue(value)) {
*userOptions = CFDictionaryCreateCopy(NULL,
(CFDictionaryRef)propertyList);
break;
}
}
}
}
return TRUE;
}
static Boolean
SCNetworkConnectionPrivateIsPPPService(SCDynamicStoreRef session, CFStringRef serviceID)
{
CFStringRef entityKey;
Boolean isPPPService = FALSE;
Boolean isModemOrPPPoE = FALSE;
entityKey = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
serviceID,
kSCEntNetInterface);
if (entityKey != NULL) {
CFDictionaryRef serviceDict;
serviceDict = SCDynamicStoreCopyValue(session, entityKey);
if (serviceDict != NULL) {
if (isA_CFDictionary(serviceDict)) {
CFStringRef type;
CFStringRef subtype;
type = CFDictionaryGetValue(serviceDict, kSCPropNetInterfaceType);
if (isA_CFString(type)) {
isPPPService = CFEqual(type, kSCValNetInterfaceTypePPP);
}
subtype = CFDictionaryGetValue(serviceDict, kSCPropNetInterfaceSubType);
if (isA_CFString(subtype)) {
isModemOrPPPoE = (CFEqual(subtype, kSCValNetInterfaceSubTypePPPSerial) ||
CFEqual(subtype, kSCValNetInterfaceSubTypePPPoE));
}
}
CFRelease(serviceDict);
}
CFRelease(entityKey);
}
return (isPPPService && isModemOrPPPoE);
}
static void
addPasswordFromKeychain(CFDictionaryRef *userOptions)
{
CFArrayRef enumerator;
CFIndex n;
CFDictionaryRef oldDict;
CFPropertyListRef uniqueID = NULL;
oldDict = *userOptions;
if(oldDict == NULL) {
return; }
uniqueID = CFDictionaryGetValue(oldDict, k_Unique_Id_Key);
if(!isA_CFString(uniqueID)) {
return; }
enumerator = copyKeychainEnumerator(uniqueID);
if(enumerator == NULL) {
return; }
n = CFArrayGetCount(enumerator);
if (n > 0) {
void *data = NULL;
UInt32 dataLen = 0;
SecKeychainItemRef itemRef;
OSStatus result;
itemRef = (SecKeychainItemRef)CFArrayGetValueAtIndex(enumerator, 0);
result = SecKeychainItemCopyContent(itemRef, NULL, NULL, &dataLen, (void *)&data); if(result == noErr && data != NULL && dataLen > 0) {
CFStringRef pass;
pass = CFStringCreateWithBytes(NULL, data, dataLen, kCFStringEncodingUTF8, TRUE);
if (pass) {
CFMutableDictionaryRef newDict;
CFMutableDictionaryRef newPPP;
CFDictionaryRef pppDict;
newDict = CFDictionaryCreateMutableCopy(NULL, 0, oldDict);
pppDict = CFDictionaryGetValue(newDict, kSCEntNetPPP);
if (isA_CFDictionary(pppDict)) {
newPPP = CFDictionaryCreateMutableCopy(NULL, 0, pppDict);
} else {
newPPP = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(newPPP, kSCPropNetPPPAuthPassword, pass);
CFRelease(pass);
CFDictionarySetValue(newDict, kSCEntNetPPP, newPPP);
CFRelease(newPPP);
CFRelease(oldDict);
*userOptions = CFDictionaryCreateCopy(NULL, newDict);
CFRelease(newDict);
}
}
}
CFRelease(enumerator);
return;
}
static CFArrayRef
copyKeychainEnumerator(CFStringRef uniqueIdentifier)
{
char *buf = NULL;
CFMutableArrayRef itemArray = NULL;
OSStatus result;
SecKeychainSearchRef search = NULL;
buf = _SC_cfstring_to_cstring(uniqueIdentifier, NULL, 0, kCFStringEncodingUTF8);
if (buf != NULL) {
SecKeychainAttribute attributes[] = {{ kSecServiceItemAttr,
CFStringGetLength(uniqueIdentifier),
(void *)buf
}};
SecKeychainAttributeList attrList = { sizeof(attributes) / sizeof(*attributes),
attributes };
result = SecKeychainSearchCreateFromAttributes(NULL, kSecGenericPasswordItemClass, &attrList, &search);
if (result == noErr) {
itemArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
while (result == noErr) {
SecKeychainItemRef itemFound = NULL;
result = SecKeychainSearchCopyNext(search, &itemFound);
if (result != noErr) {
break;
}
if (itemFound) {
CFArrayAppendValue(itemArray, itemFound);
CFRelease(itemFound);
}
}
}
}
if (search) CFRelease(search);
if (buf) CFAllocatorDeallocate(NULL, buf);
return itemArray;
}