#include <mach/mach.h>
#include <string.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <sys/errno.h>
#include <sys/signal.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <CoreFoundation/CoreFoundation.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h> // for SCLog()
#include <SystemConfiguration/SCValidation.h>
#include "ppp_msg.h"
#include "../Family/if_ppplink.h"
#include "scnc_client.h"
#include "scnc_utils.h"
CFStringRef parse_component(CFStringRef key, CFStringRef prefix)
{
CFMutableStringRef comp;
CFRange range;
if (!CFStringHasPrefix(key, prefix))
return NULL;
comp = CFStringCreateMutableCopy(NULL, 0, key);
CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
range = CFStringFind(comp, CFSTR("/"), 0);
if (range.location == kCFNotFound) {
CFRelease(comp);
return NULL;
}
range.length = CFStringGetLength(comp) - range.location;
CFStringDelete(comp, range);
return comp;
}
CFDictionaryRef copyService(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID)
{
CFTypeRef data = NULL;
CFMutableDictionaryRef service = NULL;
CFStringRef key = NULL;
int i;
CFStringRef copy[] = {
kSCEntNetPPP,
kSCEntNetModem,
kSCEntNetInterface,
kSCEntNetIPv4,
kSCEntNetIPv6,
#ifndef TARGET_EMBEDDED_OS
kSCEntNetSMB,
#endif
kSCEntNetDNS,
kSCEntNetL2TP,
kSCEntNetPPTP,
kSCEntNetIPSec,
NULL,
};
key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), domain, kSCCompNetwork, kSCCompService, serviceID);
if (key == 0)
goto fail;
data = SCDynamicStoreCopyValue(store, key);
if (data == 0) {
data = CFDictionaryCreate(NULL, 0, 0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (data == 0)
goto fail;
}
CFRelease(key);
key = NULL;
service = CFDictionaryCreateMutableCopy(NULL, 0, data);
if (service == 0)
goto fail;
CFRelease(data);
for (i = 0; copy[i]; i++) {
data = copyEntity(store, domain, serviceID, copy[i]);
if (data) {
CFDictionaryAddValue(service, copy[i], data);
CFRelease(data);
}
}
return service;
fail:
if (key)
CFRelease(key);
if (data)
CFRelease(data);
if (service)
CFRelease(service);
return 0;
}
CFDictionaryRef copyEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity)
{
CFTypeRef data = NULL;
CFStringRef key;
if (serviceID)
key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, domain, serviceID, entity);
else
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(0, domain, entity);
if (key) {
data = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
}
return data;
}
int existEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID, CFStringRef entity)
{
CFTypeRef data;
data = copyEntity(store, domain, serviceID, entity);
if (data) {
CFRelease(data);
return 1;
}
return 0;
}
int getString(CFDictionaryRef service, CFStringRef property, u_char *str, u_int16_t maxlen)
{
CFStringRef string;
CFDataRef ref;
str[0] = 0;
ref = CFDictionaryGetValue(service, property);
if (ref) {
if (CFGetTypeID(ref) == CFStringGetTypeID()) {
CFStringGetCString((CFStringRef)ref, str, maxlen, kCFStringEncodingUTF8);
return 1;
}
else if (CFGetTypeID(ref) == CFDataGetTypeID()) {
CFStringEncoding encoding;
#if __BIG_ENDIAN__
encoding = (*(CFDataGetBytePtr(ref) + 1) == 0x00) ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE;
#else // __LITTLE_ENDIAN__
encoding = (*(CFDataGetBytePtr(ref) ) == 0x00) ? kCFStringEncodingUTF16BE : kCFStringEncodingUTF16LE;
#endif
string = CFStringCreateWithBytes(NULL, (const UInt8 *)CFDataGetBytePtr(ref), CFDataGetLength(ref), encoding, FALSE);
if (string) {
CFStringGetCString((CFStringRef)string, str, maxlen, kCFStringEncodingUTF8);
CFRelease(string);
return 1;
}
}
}
return 0;
}
int getNumber(CFDictionaryRef dict, CFStringRef property, u_int32_t *outval)
{
CFNumberRef ref;
ref = CFDictionaryGetValue(dict, property);
if (ref && (CFGetTypeID(ref) == CFNumberGetTypeID())) {
CFNumberGetValue(ref, kCFNumberSInt32Type, outval);
return 1;
}
return 0;
}
int getNumberFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
CFStringRef entity, CFStringRef property, u_int32_t *outval)
{
CFTypeRef data;
int ok = 0;
if (data = copyEntity(store, domain, serviceID, entity)) {
ok = getNumber(data, property, outval);
CFRelease(data);
}
return ok;
}
int getStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
CFStringRef entity, CFStringRef property, u_char *str, u_int16_t maxlen)
{
CFTypeRef data;
int ok = 0;
data = copyEntity(store, domain, serviceID, entity);
if (data) {
ok = getString(data, property, str, maxlen);
CFRelease(data);
}
return ok;
}
CFStringRef copyCFStringFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
CFStringRef entity, CFStringRef property)
{
CFTypeRef data;
CFStringRef string, ret = 0;
data = copyEntity(store, domain, serviceID, entity);
if (data) {
string = CFDictionaryGetValue(data, property);
if (string && (CFGetTypeID(string) == CFStringGetTypeID())) {
CFRetain(string);
ret = string;
}
CFRelease(data);
}
return ret;
}
u_int32_t CFStringAddrToLong(CFStringRef string)
{
char str[100];
u_int32_t ret = 0;
if (string) {
str[0] = 0;
CFStringGetCString(string, str, sizeof(str), kCFStringEncodingMacRoman);
ret = ntohl(inet_addr(str));
}
return ret;
}
int getAddressFromEntity(SCDynamicStoreRef store, CFStringRef domain, CFStringRef serviceID,
CFStringRef entity, CFStringRef property, u_int32_t *outval)
{
CFTypeRef data;
int ok = 0;
CFArrayRef array;
data = copyEntity(store, domain, serviceID, entity);
if (data) {
array = CFDictionaryGetValue(data, property);
if (array && CFArrayGetCount(array)) {
*outval = CFStringAddrToLong(CFArrayGetValueAtIndex(array, 0));
ok = 1;
}
CFRelease(data);
}
return ok;
}
Boolean my_CFEqual(CFTypeRef obj1, CFTypeRef obj2)
{
if (obj1 == NULL && obj2 == NULL)
return true;
else if (obj1 == NULL || obj2 == NULL)
return false;
return CFEqual(obj1, obj2);
}
void my_CFRelease(void *t)
{
void * * obj = (void * *)t;
if (obj && *obj) {
CFRelease(*obj);
*obj = NULL;
}
return;
}
void my_close(int fd)
{
if (fd != -1)
close(fd);
}
CFTypeRef my_CFRetain(CFTypeRef obj)
{
if (obj)
CFRetain(obj);
return obj;
}
Boolean isDictionary (CFTypeRef obj)
{
return (obj && CFGetTypeID(obj) == CFDictionaryGetTypeID());
}
Boolean isArray (CFTypeRef obj)
{
return (obj && CFGetTypeID(obj) == CFArrayGetTypeID());
}
Boolean isString (CFTypeRef obj)
{
return (obj && CFGetTypeID(obj) == CFStringGetTypeID());
}
Boolean isNumber (CFTypeRef obj)
{
return (obj && CFGetTypeID(obj) == CFNumberGetTypeID());
}
Boolean isData (CFTypeRef obj)
{
return (obj && CFGetTypeID(obj) == CFDataGetTypeID());
}
void AddNumber(CFMutableDictionaryRef dict, CFStringRef property, u_int32_t nunmber)
{
CFNumberRef num;
num = CFNumberCreate(NULL, kCFNumberSInt32Type, &nunmber);
if (num) {
CFDictionaryAddValue(dict, property, num);
CFRelease(num);
}
}
void AddString(CFMutableDictionaryRef dict, CFStringRef property, char *string)
{
CFStringRef str;
str = CFStringCreateWithCString(NULL, string, kCFStringEncodingUTF8);
if (str) {
CFDictionaryAddValue(dict, property, str);
CFRelease(str);
}
}
void AddNumberFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict)
{
u_int32_t lval;
if (getNumberFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property, &lval))
AddNumber(dict, property, lval);
}
void AddStringFromState(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef entity, CFStringRef property, CFMutableDictionaryRef dict)
{
CFStringRef string;
if (string = copyCFStringFromEntity(store, kSCDynamicStoreDomainState, serviceID, entity, property)) {
CFDictionaryAddValue(dict, property, string);
CFRelease(string);
}
}
CFDataRef Serialize(CFPropertyListRef obj, void **data, u_int32_t *dataLen)
{
CFDataRef xml;
xml = CFPropertyListCreateXMLData(NULL, obj);
if (xml) {
*data = (void*)CFDataGetBytePtr(xml);
*dataLen = CFDataGetLength(xml);
}
return xml;
}
CFPropertyListRef Unserialize(void *data, u_int32_t dataLen)
{
CFDataRef xml;
CFPropertyListRef ref = 0;
xml = CFDataCreate(NULL, data, dataLen);
if (xml) {
ref = CFPropertyListCreateFromXMLData(NULL,
xml, kCFPropertyListImmutable, NULL);
CFRelease(xml);
}
return ref;
}
void *my_Allocate(int size)
{
void *addr;
kern_return_t status;
status = vm_allocate(mach_task_self(), (vm_address_t *)&addr, size, TRUE);
if (status != KERN_SUCCESS) {
return 0;
}
return addr;
}
void my_Deallocate(void * addr, int size)
{
kern_return_t status;
if (addr == 0)
return;
status = vm_deallocate(mach_task_self(), (vm_address_t)addr, size);
if (status != KERN_SUCCESS) {
}
return;
}
Boolean GetIntFromDict (CFDictionaryRef dict, CFStringRef property, u_int32_t *outval, u_int32_t defaultval)
{
CFNumberRef ref;
ref = CFDictionaryGetValue(dict, property);
if (isNumber(ref)
&& CFNumberGetValue(ref, kCFNumberSInt32Type, outval))
return TRUE;
*outval = defaultval;
return FALSE;
}
int GetStrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen, char *defaultval)
{
CFStringRef ref;
ref = CFDictionaryGetValue(dict, property);
if (!isString(ref)
|| !CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8))
strncpy(outstr, defaultval, maxlen);
return strlen(outstr);
}
Boolean GetStrAddrFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen)
{
CFStringRef ref;
in_addr_t addr;
ref = CFDictionaryGetValue(dict, property);
if (isString(ref)
&& CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) {
addr = inet_addr(outstr);
return addr != INADDR_NONE;
}
return FALSE;
}
Boolean GetStrNetFromDict (CFDictionaryRef dict, CFStringRef property, char *outstr, int maxlen)
{
CFStringRef ref;
in_addr_t net;
ref = CFDictionaryGetValue(dict, property);
if (isString(ref)
&& CFStringGetCString(ref, outstr, maxlen, kCFStringEncodingUTF8)) {
net = inet_network(outstr);
return net != INADDR_NONE; }
return FALSE;
}
int publish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry, CFTypeRef value)
{
CFMutableDictionaryRef dict;
CFPropertyListRef ref;
if (ref = SCDynamicStoreCopyValue(store, key)) {
dict = CFDictionaryCreateMutableCopy(0, 0, ref);
CFRelease(ref);
}
else
dict = CFDictionaryCreateMutable(0, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (dict == 0)
return 0;
CFDictionarySetValue(dict, entry, value);
if (SCDynamicStoreSetValue(store, key, dict) == 0)
; CFRelease(dict);
return 1;
}
int unpublish_keyentry(SCDynamicStoreRef store, CFStringRef key, CFStringRef entry)
{
CFMutableDictionaryRef dict;
CFPropertyListRef ref;
if (ref = SCDynamicStoreCopyValue(store, key)) {
if (dict = CFDictionaryCreateMutableCopy(0, 0, ref)) {
CFDictionaryRemoveValue(dict, entry);
if (SCDynamicStoreSetValue(store, key, dict) == 0)
; CFRelease(dict);
}
CFRelease(ref);
}
return 0;
}
int publish_dictnumentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, int val)
{
int ret = ENOMEM;
CFNumberRef num;
CFStringRef key;
key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
if (key) {
num = CFNumberCreate(NULL, kCFNumberIntType, &val);
if (num) {
ret = publish_keyentry(store, key, entry, num);
CFRelease(num);
ret = 0;
}
CFRelease(key);
}
return ret;
}
int unpublish_dictentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry)
{
int ret = ENOMEM;
CFStringRef key;
key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
if (key) {
ret = unpublish_keyentry(store, key, entry);
CFRelease(key);
ret = 0;
}
return ret;
}
int unpublish_dict(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict)
{
int ret = ENOMEM;
CFStringRef key;
if (!store)
return -1;
if (dict)
key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
else
key = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/%@"), kSCDynamicStoreDomainState, kSCCompNetwork, kSCCompService, serviceID);
if (key) {
SCDynamicStoreRemoveValue(store, key);
CFRelease(key);
ret = 0;
}
return ret;
}
int publish_dictstrentry(SCDynamicStoreRef store, CFStringRef serviceID, CFStringRef dict, CFStringRef entry, char *str, int encoding)
{
int ret = ENOMEM;
CFStringRef ref;
CFStringRef key;
key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainState, serviceID, dict);
if (key) {
ref = CFStringCreateWithCString(NULL, str, encoding);
if (ref) {
ret = publish_keyentry(store, key, entry, ref);
CFRelease(ref);
ret = 0;
}
CFRelease(key);
}
return ret;
}
int
cfstring_is_ip(CFStringRef str)
{
char buf[32];
struct in_addr ip = { 0 };
CFIndex l;
int n;
CFRange range;
if (!isString(str))
return 0;
range = CFRangeMake(0, CFStringGetLength(str));
n = CFStringGetBytes(str, range, kCFStringEncodingMacRoman,
0, FALSE, (UInt8 *)buf, sizeof(buf), &l);
buf[l] = '\0';
return inet_aton(buf, &ip);
}
CFStringRef
copyPrimaryService (SCDynamicStoreRef store)
{
CFDictionaryRef dict;
CFStringRef key;
CFStringRef primary = NULL;
if ((key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainState,
kSCEntNetIPv4)) == NULL) {
return NULL;
}
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (isA_CFDictionary(dict)) {
primary = CFDictionaryGetValue(dict,
kSCDynamicStorePropNetPrimaryService);
primary = isA_CFString(primary);
if (primary)
CFRetain(primary);
}
if (dict != NULL) {
CFRelease(dict);
}
return primary;
}
Boolean UpdatePasswordPrefs(CFStringRef serviceID, CFStringRef interfaceType, SCNetworkInterfacePasswordType passwordType,
CFStringRef passwordEncryptionKey, CFStringRef passwordEncryptionValue, CFStringRef logTitle)
{
SCPreferencesRef prefs = NULL;
SCNetworkServiceRef service = NULL;
SCNetworkInterfaceRef interface = NULL;
CFMutableDictionaryRef newConfig = NULL;
CFDictionaryRef config;
Boolean ok, locked = FALSE, success = FALSE;
prefs = SCPreferencesCreate(NULL, CFSTR("UpdatePassword"), NULL);
if (prefs == NULL) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCreate fails"), logTitle);
goto done;
}
ok = SCPreferencesLock(prefs, TRUE);
if (!ok) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesLock fails"), logTitle);
goto done;
}
locked = TRUE;
service = SCNetworkServiceCopy(prefs, serviceID);
if (service == NULL) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkServiceCopy fails"), logTitle);
goto done;
}
interface = SCNetworkServiceGetInterface(service);
if ((interface == NULL) || !CFEqual(SCNetworkInterfaceGetInterfaceType(interface), interfaceType)) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: interface not %@"), logTitle, interfaceType);
goto done;
}
if (SCNetworkInterfaceCheckPassword(interface, passwordType)) {
ok = SCNetworkInterfaceRemovePassword(interface, passwordType);
if (!ok) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceRemovePassword fails"), logTitle);
}
}
config = SCNetworkInterfaceGetConfiguration(interface);
if (config != NULL) {
newConfig = CFDictionaryCreateMutableCopy(NULL, 0, config);
}
else {
newConfig = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
if (newConfig == NULL) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: cannot allocate new interface configuration"), logTitle);
goto done;
}
if (passwordEncryptionValue) {
CFDictionarySetValue(newConfig, passwordEncryptionKey, passwordEncryptionValue);
} else {
CFDictionaryRemoveValue( newConfig, passwordEncryptionKey);
}
ok = SCNetworkInterfaceSetConfiguration(interface, newConfig);
if ( !ok ) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: SCNetworkInterfaceSetConfiguration fails"), logTitle);
goto done;
}
ok = SCPreferencesCommitChanges(prefs);
if (!ok) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesCommitChanges fails"), logTitle);
goto done;
}
ok = SCPreferencesApplyChanges(prefs);
if (!ok) {
SCLog(TRUE, LOG_ERR, CFSTR("%@: SCPreferencesApplyChanges fails"), logTitle);
goto done;
}
success = TRUE;
done :
if (newConfig!= NULL) {
CFRelease(newConfig);
}
if (service != NULL) {
CFRelease(service);
}
if (locked) {
SCPreferencesUnlock(prefs);
}
if (prefs != NULL) {
CFRelease(prefs);
}
return success;
}