#include "KEXTPrivate.h"
#include "vers_rsrc.h"
#include "CFAdditions.h"
#include <IOKit/IOKitServer.h>
#include <IOKit/IOKitLib.h>
#include <sys/stat.h>
#include <stdarg.h>
#include <IOKit/IOCFURLAccess.h>
static KEXTReturn
URLResourceExists(
CFURLRef url );
static KEXTReturn
URLResourceCreateModifcationTime(
CFURLRef url,
CFDateRef * date );
static KEXTReturn
URLResourceCreateData(
CFURLRef url,
CFDataRef * data );
static void
ArrayAddModuleEntities(
KEXTModuleRef module,
KEXTManagerRef manager );
static void
ArrayAddPersonalityEntities(
KEXTPersonalityRef personality,
KEXTManagerRef manager );
#if 0
static void
ArrayAddConfigEntities(
KEXTConfigRef config,
KEXTManagerRef manager );
#endif
static void
ArrayRemoveModuleEntities(
KEXTModuleRef module,
KEXTManagerRef manager );
static void
ArrayRemovePersonalityEntities(
KEXTPersonalityRef personality,
KEXTManagerRef manager );
#if 0
static void
ArrayRemoveConfigEntities(
KEXTConfigRef config,
KEXTManagerRef manager );
#endif
static void
DictionaryCopyAllBundles(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array );
static void
DictionaryCopyAllModules(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array );
static void
DictionaryCopyAllPersonalities(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array );
static void
DictionaryCopyAllConfigs(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array );
static void
_KEXTManagerAddRelation(
CFMutableDictionaryRef relationsDict,
KEXTEntityRef entity );
static void
_KEXTManagerRemoveRelation(
CFMutableDictionaryRef relationsDict,
KEXTEntityRef entity );
static void
_KEXTManagerAddBundleEntity(
KEXTManagerRef manager,
KEXTBundleRef bundle );
static KEXTReturn
_KEXTManagerAddBundle(
KEXTManagerRef manager,
CFURLRef bundleUrl,
Boolean toplevel);
static void
_KEXTManagerAddModuleEntity(
KEXTManagerRef manager,
KEXTModuleRef module );
static void
_KEXTManagerAddPersonalityEntity(
KEXTManagerRef manager,
KEXTPersonalityRef personality );
static void
_KEXTManagerAddConfigEntity(
KEXTManagerRef manager,
KEXTConfigRef config );
static void
_KEXTManagerRemoveBundleEntity(
KEXTManagerRef manager,
KEXTBundleRef bundle );
static void
_KEXTManagerRemoveModuleEntity(
KEXTManagerRef manager,
KEXTModuleRef module );
static void
_KEXTManagerRemovePersonalityEntity(
KEXTManagerRef manager,
KEXTPersonalityRef personality );
static void
_KEXTManagerRemoveConfigEntity(
KEXTManagerRef manager,
KEXTConfigRef config );
static void
_KEXTManagerRemoveBundleItemsOnly(
KEXTManagerRef manager,
KEXTBundleRef bundle );
void
_KEXTManagerRemoveConfigEntityWithCallback(
KEXTManagerRef manager,
KEXTConfigRef config );
static KEXTReturn
_KEXTManagerScanBundles(
KEXTManagerRef manager,
CFURLRef url,
Boolean toplevel);
static void _KEXTManagerLogError(KEXTManagerRef manager,
CFStringRef string, ...);
static void _KEXTManagerLogMessage(KEXTManagerRef manager,
CFStringRef string, ...);
static KEXTReturn
URLResourceExists(
CFURLRef url )
{
CFBooleanRef val;
Boolean boolval;
SInt32 err;
if ( !url ) {
return kKEXTReturnBadArgument;
}
val = IOURLCreatePropertyFromResource(
kCFAllocatorDefault,
url,
kIOURLFileExists,
&err);
if ( !val ) {
return kKEXTReturnBundleNotFound;
}
boolval = CFBooleanGetValue(val);
CFRelease(val);
if ( !boolval ) {
return kKEXTReturnBundleNotFound;
}
return kKEXTReturnSuccess;
}
static KEXTReturn
URLResourceCreateModifcationTime(
CFURLRef url,
CFDateRef * date )
{
SInt32 err;
if ( !url || !date ) {
return kKEXTReturnBadArgument;
}
*date = IOURLCreatePropertyFromResource(
kCFAllocatorDefault,
url,
kIOURLFileLastModificationTime,
&err);
if ( !*date ) {
return kKEXTReturnError;
}
return kKEXTReturnSuccess;
}
static KEXTReturn
URLResourceCreateData(
CFURLRef url,
CFDataRef * data )
{
Boolean val;
SInt32 err;
*data = NULL;
val = IOURLCreateDataAndPropertiesFromResource(
kCFAllocatorDefault,
url,
data,
NULL,
NULL,
&err);
if ( !val ) {
if ( *data ) {
CFRelease(*data);
*data = NULL;
}
return kKEXTReturnResourceNotFound;
}
return kKEXTReturnSuccess;
}
static Boolean
_KEXTManagerIsKernelExtensionURL(CFURLRef url)
{
CFStringRef path = CFURLGetString(url);
return ( CFStringHasSuffix(path, CFSTR("kext"))
|| CFStringHasSuffix(path, CFSTR("kext/")) );
}
static CFURLRef
_KEXTManagerCreateURLForModule(
KEXTManagerRef manager,
KEXTModuleRef module )
{
KEXTReturn error;
KEXTBundleRef bundle;
CFStringRef primaryKey;
CFStringRef file;
primaryKey = KEXTModuleGetPrimaryKey(module);
if ( !primaryKey) {
return NULL;
}
bundle = KEXTManagerGetBundleWithModule(manager, primaryKey);
if ( !bundle ) {
return NULL;
}
file = KEXTModuleGetProperty(module, CFSTR(kModuleFileKey));
if ( !file ) {
return NULL;
}
return KEXTBundleCreateURLForResource(bundle, file, NULL, &error);
}
static void
_KEXTManagerAddRelation(
CFMutableDictionaryRef relationsDict,
KEXTEntityRef entity )
{
CFStringRef parentKey;
CFStringRef primaryKey;
CFMutableArrayRef keyArray;
CFIndex count;
parentKey = CFDictionaryGetValue(entity, CFSTR("ParentKey"));
if ( !parentKey ) {
return;
}
keyArray = (CFMutableArrayRef)CFDictionaryGetValue(relationsDict, parentKey);
if ( !keyArray ) {
keyArray = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if ( !keyArray ) {
return;
}
CFDictionarySetValue(relationsDict, parentKey, keyArray);
CFRelease(keyArray);
}
count = CFArrayGetCount(keyArray);
primaryKey = CFDictionaryGetValue(entity, CFSTR("PrimaryKey"));
if( !CFArrayContainsValue(keyArray, CFRangeMake(0, count), primaryKey) ) {
CFArrayAppendValue(keyArray, primaryKey);
}
}
static void
_KEXTManagerRemoveRelation(
CFMutableDictionaryRef relationsDict,
KEXTEntityRef entity )
{
CFStringRef parentKey;
CFStringRef primaryKey;
CFMutableArrayRef keyArray;
CFIndex count;
CFIndex index;
parentKey = CFDictionaryGetValue(entity, CFSTR("ParentKey"));
primaryKey = CFDictionaryGetValue(entity, CFSTR("PrimaryKey"));
if ( !parentKey || !primaryKey ) {
return;
}
keyArray = (CFMutableArrayRef)CFDictionaryGetValue(relationsDict, parentKey);
if ( !keyArray ) {
return;
}
count = CFArrayGetCount(keyArray);
index = CFArrayGetFirstIndexOfValue(keyArray, CFRangeMake(0, count), primaryKey);
if ( index != -1 ) {
CFArrayRemoveValueAtIndex(keyArray, index);
}
}
static inline KEXTEntityRef
_KEXTManagerGetEntityWithKey(
KEXTManagerRef manager,
CFStringRef primaryKey )
{
return (KEXTEntityRef)CFDictionaryGetValue(deref(manager)->_entities, primaryKey);
}
static inline void
_KEXTManagerAddEntity(
KEXTManagerRef manager,
KEXTEntityRef entity )
{
CFStringRef primaryKey;
primaryKey = CFDictionaryGetValue(entity, CFSTR("PrimaryKey"));
if ( primaryKey ) {
CFDictionarySetValue(deref(manager)->_entities, primaryKey, entity);
}
}
static void
_KEXTManagerAddBundleEntity(
KEXTManagerRef manager,
KEXTBundleRef bundle )
{
CFURLRef url;
CFStringRef primaryKey;
if ( !manager || !bundle ) {
return;
}
_KEXTManagerAddEntity(manager, bundle);
url = KEXTBundleCopyURL(bundle);
if ( url ) {
primaryKey = KEXTBundleGetPrimaryKey(bundle);
CFDictionarySetValue(deref(manager)->_urlRels, url, primaryKey);
CFRelease(url);
}
}
static void
_KEXTManagerAddModuleEntity(
KEXTManagerRef manager,
KEXTModuleRef module )
{
if ( !manager || !module ) {
return;
}
_KEXTManagerAddEntity(manager, module);
_KEXTManagerAddRelation(deref(manager)->_modRels, module);
}
static void
_KEXTManagerAddPersonalityEntity(
KEXTManagerRef manager,
KEXTPersonalityRef personality )
{
if ( !manager || !personality ) {
return;
}
_KEXTManagerAddEntity(manager, personality);
_KEXTManagerAddRelation(deref(manager)->_perRels, personality);
}
static void
_KEXTManagerAddConfigEntity(
KEXTManagerRef manager,
KEXTConfigRef config )
{
if ( !manager || !config ) {
return;
}
_KEXTManagerAddEntity(manager, config);
_KEXTManagerAddRelation(deref(manager)->_cfgRels, config);
}
static inline void
_KEXTManagerRemoveEntity(
KEXTManagerRef manager,
KEXTEntityRef entity )
{
CFStringRef primaryKey;
primaryKey = CFDictionaryGetValue(entity, CFSTR("PrimaryKey"));
if ( primaryKey ) {
CFDictionaryRemoveValue(deref(manager)->_entities, primaryKey);
}
}
static void
_KEXTManagerRemoveBundleEntity(
KEXTManagerRef manager,
KEXTBundleRef bundle )
{
CFURLRef url;
if ( !manager || !bundle ) {
return;
}
url = KEXTBundleCopyURL(bundle);
if ( url ) {
CFDictionaryRemoveValue(deref(manager)->_urlRels, url);
CFRelease(url);
}
_KEXTManagerRemoveEntity(manager, bundle);
}
static void
_KEXTManagerRemoveModuleEntity(
KEXTManagerRef manager,
KEXTModuleRef module )
{
if ( !manager || !module ) {
return;
}
_KEXTManagerRemoveEntity(manager, module);
_KEXTManagerRemoveRelation(deref(manager)->_modRels, module);
}
static void
_KEXTManagerRemovePersonalityEntity(
KEXTManagerRef manager,
KEXTPersonalityRef personality )
{
if ( !manager || !personality ) {
return;
}
_KEXTManagerRemoveEntity(manager, personality);
_KEXTManagerRemoveRelation(deref(manager)->_perRels, personality);
}
static void
_KEXTManagerRemoveConfigEntity(
KEXTManagerRef manager,
KEXTConfigRef config )
{
if ( !manager || !config ) {
return;
}
_KEXTManagerRemoveEntity(manager, config);
_KEXTManagerRemoveRelation(deref(manager)->_cfgRels, config);
}
static CFArrayRef
_KEXTManagerGetModuleKeysForBundle(
KEXTManagerRef manager,
KEXTBundleRef bundle )
{
CFStringRef key;
key = KEXTBundleGetPrimaryKey(bundle);
return CFDictionaryGetValue(deref(manager)->_modRels, key);
}
static CFArrayRef
_KEXTManagerGetPersonalityKeysForBundle(
KEXTManagerRef manager,
KEXTBundleRef bundle )
{
CFStringRef key;
key = KEXTBundleGetPrimaryKey(bundle);
return CFDictionaryGetValue(deref(manager)->_perRels, key);
}
static CFArrayRef
_KEXTManagerGetConfigKeysForBundle(
KEXTManagerRef manager,
KEXTBundleRef bundle )
{
CFStringRef key;
key = KEXTBundleGetPrimaryKey(bundle);
return CFDictionaryGetValue(deref(manager)->_cfgRels, key);
}
static void
ArrayAddModuleEntities(
KEXTModuleRef module,
KEXTManagerRef manager )
{
_KEXTManagerAddModuleEntity(manager, module);
}
static void
ArrayAddPersonalityEntities(
KEXTPersonalityRef personality,
KEXTManagerRef manager )
{
_KEXTManagerAddPersonalityEntity(manager, personality);
}
#if 0
static void
ArrayAddConfigEntities(
KEXTConfigRef config,
KEXTManagerRef manager )
{
_KEXTManagerAddConfigEntity(manager, config);
}
#endif
static void
ArrayRemoveModuleEntities(
KEXTModuleRef module,
KEXTManagerRef manager )
{
_KEXTManagerRemoveModuleEntity(manager, module);
}
static void
ArrayRemovePersonalityEntities(
KEXTPersonalityRef personality,
KEXTManagerRef manager )
{
_KEXTManagerRemovePersonalityEntity(manager, personality);
}
#if 0
static void
ArrayRemoveConfigEntities(
KEXTConfigRef config,
KEXTManagerRef manager )
{
_KEXTManagerRemoveConfigEntity(manager, config);
}
#endif
static void
DictionaryCopyAllBundles(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array )
{
CFStringRef type;
type = KEXTManagerGetEntityType(entity);
if ( CFEqual(type, KEXTBundleGetEntityType()) ) {
CFArrayAppendValue(array, entity);
}
}
static void
DictionaryCopyAllModules(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array )
{
CFStringRef type;
type = KEXTManagerGetEntityType(entity);
if ( CFEqual(type, KEXTModuleGetEntityType()) ) {
CFArrayAppendValue(array, entity);
}
}
static void
DictionaryCopyAllPersonalities(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array )
{
CFStringRef type;
CFBooleanRef prop;
prop = CFDictionaryGetValue(entity, CFSTR("IsConfig"));
if ( prop && CFEqual(prop, kCFBooleanTrue) ) {
return;
}
type = KEXTManagerGetEntityType(entity);
if ( CFEqual(type, KEXTPersonalityGetEntityType()) ) {
CFArrayAppendValue(array, entity);
}
}
static void
DictionaryCopyAllConfigs(
CFStringRef key,
KEXTEntityRef entity,
CFMutableArrayRef array )
{
CFStringRef type;
CFBooleanRef prop;
prop = CFDictionaryGetValue(entity, CFSTR("IsConfig"));
if ( !prop || !CFEqual(prop, kCFBooleanTrue) ) {
return;
}
type = KEXTManagerGetEntityType(entity);
if ( CFEqual(type, KEXTPersonalityGetEntityType()) ) {
CFArrayAppendValue(array, entity);
}
}
static void
ArrayCopyEntityForKey(
CFStringRef key,
void * context[] )
{
KEXTManagerRef manager;
KEXTEntityRef entity;
CFMutableArrayRef array;
manager = context[0];
array = context[1];
entity = _KEXTManagerGetEntityWithKey(manager, key);
if ( entity ) {
CFArrayAppendValue(array, entity);
}
}
static void ArrayGatherDependencyPaths(const void * val, void * context[])
{
KEXTManagerRef manager;
KEXTModuleRef module;
CFMutableArrayRef array;
CFStringRef path;
CFURLRef url;
module = (KEXTModuleRef)val;
manager = context[0];
array = context[1];
url = _KEXTManagerCreateURLForModule(manager, module);
if ( !url ) {
return;
}
path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
CFRelease(url);
if ( !path ) {
return;
}
CFArrayAppendValue(array, path);
CFRelease(path);
}
Boolean KEXTManagerCheckSafeBootForModule(
KEXTManagerRef manager,
KEXTModuleRef module)
{
Boolean result = false;
CFStringRef modSafe;
if (!deref(manager)->_safeBoot) {
result = true;
goto finish;
}
modSafe = KEXTModuleGetProperty(module, CFSTR("OSBundleRequired"));
if (!modSafe) {
result = false;
goto finish;
}
if (kCFCompareEqualTo == CFStringCompare(modSafe, CFSTR("Root"), 0) ||
kCFCompareEqualTo == CFStringCompare(modSafe, CFSTR("Local-Root"), 0) ||
kCFCompareEqualTo == CFStringCompare(modSafe, CFSTR("Network-Root"), 0) ||
kCFCompareEqualTo == CFStringCompare(modSafe, CFSTR("Console"), 0) ||
kCFCompareEqualTo == CFStringCompare(modSafe, CFSTR("Safe Boot"), 0) ) {
result = true;
goto finish;
}
finish:
return result;
}
static KEXTReturn
_KEXTManagerLoadModule(
KEXTManagerRef manager,
KEXTModuleRef module,
CFArrayRef dependencies )
{
KEXTReturn error;
CFMutableArrayRef paths;
CFStringRef primaryKey;
CFStringRef mode;
CFStringRef moduleName;
CFRange range;
void * params[2];
if ( !module || !manager ) {
return kKEXTReturnBadArgument;
}
primaryKey = KEXTModuleGetPrimaryKey(module);
if ( !primaryKey ) {
return kKEXTReturnError;
}
moduleName = KEXTModuleGetProperty(module, CFSTR(kNameKey));
if ( !moduleName ) {
return kKEXTReturnError;
}
mode = CFDictionaryGetValue(deref(manager)->_noloads, primaryKey);
if ( mode && CFEqual(mode, CFSTR("Disabled")) ) {
_KEXTManagerLogError(manager,
CFSTR("Extension %@ is disabled.\n"), moduleName);
return kKEXTReturnModuleDisabled;
}
paths = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !paths ) {
return kKEXTReturnNoMemory;
}
params[0] = manager;
params[1] = paths;
range = CFRangeMake(0, CFArrayGetCount(dependencies));
CFArrayApplyFunction(
dependencies,
range,
(CFArrayApplierFunction)ArrayGatherDependencyPaths,
params);
error = kKEXTReturnError;
do {
CFURLRef url;
CFStringRef path;
url = _KEXTManagerCreateURLForModule(manager, module);
if ( !url ) {
error = kKEXTReturnNoMemory;
break;
}
path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
CFRelease(url);
if ( !path ) {
error = kKEXTReturnNoMemory;
break;
}
error = KEXTLoadModule(path, paths);
CFRelease(path);
} while ( false );
CFRelease(paths);
return error;
}
KEXTReturn
_KEXTManagerUnloadPersonality(
KEXTManagerRef manager,
KEXTPersonalityRef personality )
{
KEXTReturn error;
CFDictionaryRef matchingDict;
if ( !manager || !personality ) {
return kKEXTReturnBadArgument;
}
matchingDict = _KEXTPersonalityGetProperties(personality);
error = KEXTSendDataToCatalog(deref(manager)->_catPort,
kIOCatalogRemoveDrivers,
matchingDict);
if ( error != kKEXTReturnSuccess ) {
return error;
}
return kKEXTReturnSuccess;
}
static KEXTReturn
BundleAuthenticateCallback(
CFURLRef url,
void * context )
{
return KEXTManagerAuthenticateURL(url);
}
#define kAdministratorUID 0
KEXTReturn
KEXTManagerAuthenticateURL(
CFURLRef url )
{
KEXTReturn error;
CFArrayRef attribs;
CFDictionaryRef dict;
Boolean ret;
SInt32 err;
CFNumberRef uid = NULL;
const void * vals[] = {
kIOURLFileExists, kIOURLFileOwnerID, kIOURLFilePOSIXMode
};
dict = NULL;
if ( !url || (CFGetTypeID(url) != CFURLGetTypeID()) ) {
return kKEXTReturnBadArgument;
}
attribs = CFArrayCreate(kCFAllocatorDefault, vals, 3, &kCFTypeArrayCallBacks);
if ( !attribs ) {
return kKEXTReturnNoMemory;
}
error = kKEXTReturnError;
ret = IOURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, NULL, &dict, attribs, &err);
CFRelease(attribs);
if ( ret ) do {
SInt32 uidVal;
mode_t modeVal;
CFBooleanRef cfbool;
CFNumberRef mode;
cfbool = CFDictionaryGetValue(dict, kIOURLFileExists);
if (!cfbool || !CFBooleanGetValue(cfbool)) {
error = kKEXTReturnResourceNotFound;
break;
}
uid = CFDictionaryGetValue(dict, kIOURLFileOwnerID);
if (!uid || !CFNumberGetValue(uid, kCFNumberSInt32Type, &uidVal)
|| uidVal != kAdministratorUID) {
error = kKEXTReturnPermissionError;
break;
}
mode = CFDictionaryGetValue(dict, kIOURLFilePOSIXMode);
if ( !mode ) {
error = kKEXTReturnError;
break;
}
if ( !CFNumberGetValue(mode, kCFNumberShortType, &modeVal) ) {
error = kKEXTReturnError;
break;
}
if ( (modeVal & S_IWOTH) ||
(modeVal & S_IWGRP) ) {
error = kKEXTReturnPermissionError;
}
error = kKEXTReturnSuccess;
} while ( false );
if ( dict )
CFRelease(dict);
return error;
}
KEXTManagerRef
KEXTManagerCreate(
KEXTManagerBundleLoadingCallbacks * bundleCallbacks,
KEXTManagerModuleLoadingCallbacks * moduleCallbacks,
KEXTManagerPersonalityLoadingCallbacks * personalityCallbacks,
KEXTManagerConfigsCallbacks * configsCallbacks,
void * context,
void (* logErrorCallback)(const char * s),
void (* logMessageCallback)(const char * s),
Boolean safeBoot,
KEXTReturn * error )
{
KEXTManager * manager;
*error = kKEXTReturnSuccess;
manager = (KEXTManager *)malloc(sizeof(KEXTManager));
if ( !manager )
return NULL;
memset(manager, '\0', sizeof(KEXTManager));
manager->_refcount = 1;
manager->_safeBoot = safeBoot;
manager->_context = context;
manager->_logErrorFunc = logErrorCallback;
manager->_logMessageFunc = logMessageCallback;
*error = KERN2KEXTReturn(IOMasterPort(bootstrap_port, &manager->_catPort));
if ( *error != kKEXTReturnSuccess ) {
KEXTManagerFree((KEXTManagerRef)manager);
return NULL;
}
manager->_entities = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
manager->_urlRels = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
manager->_modRels = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
manager->_perRels = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
manager->_cfgRels = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
manager->_noloads = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if ( !manager->_entities ) {
KEXTManagerFree((KEXTManagerRef)manager);
*error = kKEXTReturnNoMemory;
return NULL;
}
manager->bcb.BundleAuthentication = BundleAuthenticateCallback;
if ( bundleCallbacks ) {
manager->bcb.BundleWillAdd = bundleCallbacks->BundleWillAdd;
manager->bcb.BundleWillRemove = bundleCallbacks->BundleWillRemove;
manager->bcb.BundleWasAdded = bundleCallbacks->BundleWasAdded;
manager->bcb.BundleWasRemoved = bundleCallbacks->BundleWasRemoved;
if ( bundleCallbacks->BundleAuthentication )
manager->bcb.BundleAuthentication = bundleCallbacks->BundleAuthentication;
}
if ( moduleCallbacks ) {
manager->mcb.ModuleWillLoad = moduleCallbacks->ModuleWillLoad;
manager->mcb.ModuleWasLoaded = moduleCallbacks->ModuleWasLoaded;
manager->mcb.ModuleError = moduleCallbacks->ModuleError;
manager->mcb.ModuleWillUnload = moduleCallbacks->ModuleWillUnload;
manager->mcb.ModuleWasUnloaded = moduleCallbacks->ModuleWasUnloaded;
}
if ( personalityCallbacks ) {
manager->pcb.PersonalityWillLoad = personalityCallbacks->PersonalityWillLoad;
manager->pcb.PersonalityWasLoaded = personalityCallbacks->PersonalityWasLoaded;
manager->pcb.PersonalityError = personalityCallbacks->PersonalityError;
manager->pcb.PersonalityWillUnload = personalityCallbacks->PersonalityWillUnload;
manager->pcb.PersonalityWasUnloaded = personalityCallbacks->PersonalityWasUnloaded;
}
if ( configsCallbacks ) {
manager->ccb.ConfigWillAdd = configsCallbacks->ConfigWillAdd;
manager->ccb.ConfigWasAdded = configsCallbacks->ConfigWasAdded;
manager->ccb.ConfigWillRemove = configsCallbacks->ConfigWillRemove;
manager->ccb.ConfigWasRemoved = configsCallbacks->ConfigWasRemoved;
}
manager->_mode = kKEXTManagerDefaultMode;
manager->_configsDate = NULL;
return (KEXTManagerRef)manager;
}
KEXTManagerRef
KEXTManagerRetain(
KEXTManagerRef manager )
{
deref(manager)->_refcount++;
return manager;
}
void
KEXTManagerRelease(
KEXTManagerRef manager )
{
deref(manager)->_refcount--;
if ( deref(manager)->_refcount < 1 ) {
KEXTManagerFree(manager);
}
}
void
KEXTManagerFree(
KEXTManagerRef manager )
{
if ( deref(manager)->_entities ) {
CFRelease(deref(manager)->_entities);
}
if ( deref(manager)->_modRels) {
CFRelease(deref(manager)->_modRels);
}
if ( deref(manager)->_perRels) {
CFRelease(deref(manager)->_perRels);
}
if ( deref(manager)->_urlRels) {
CFRelease(deref(manager)->_urlRels);
}
if ( deref(manager)->_noloads ) {
CFRelease(deref(manager)->_noloads);
}
if ( deref(manager)->_cfgRels ) {
CFRelease(deref(manager)->_cfgRels);
}
if ( deref(manager)->_configsDate ) {
CFRelease(deref(manager)->_configsDate);
}
free(manager);
}
void
KEXTManagerSetMode(
KEXTManagerRef manager,
KEXTManagerMode mode )
{
if ( !manager) {
return;
}
deref(manager)->_mode = mode;
}
void
KEXTManagerReset(
KEXTManagerRef manager )
{
CFDictionaryRemoveAllValues(deref(manager)->_entities);
CFDictionaryRemoveAllValues(deref(manager)->_modRels);
CFDictionaryRemoveAllValues(deref(manager)->_perRels);
CFDictionaryRemoveAllValues(deref(manager)->_cfgRels);
CFDictionaryRemoveAllValues(deref(manager)->_noloads);
}
static inline CFArrayRef
_KEXTManagerCopyRelationsForBundle(
CFMutableDictionaryRef relationsDict,
KEXTBundleRef bundle )
{
CFStringRef primaryKey;
CFArrayRef array;
primaryKey = KEXTBundleGetPrimaryKey(bundle);
if ( !primaryKey ) {
return NULL;
}
array = CFDictionaryGetValue(relationsDict, primaryKey);
if ( !array ) {
return NULL;
}
return CFArrayCreateCopy(kCFAllocatorDefault, array);
}
CFArrayRef
KEXTManagerCopyModulesForBundle(
KEXTManagerRef manager,
KEXTBundleRef bundle)
{
CFMutableArrayRef array;
CFArrayRef moduleKeys;
CFRange range;
void * context[2];
moduleKeys = _KEXTManagerGetModuleKeysForBundle(manager, bundle);
if ( !moduleKeys ) {
return NULL;
}
array = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if ( !array ) {
return NULL;
}
context[0] = manager;
context[1] = array;
range = CFRangeMake(0, CFArrayGetCount(moduleKeys));
CFArrayApplyFunction(moduleKeys, range, (CFArrayApplierFunction)ArrayCopyEntityForKey, context);
return array;
}
CFArrayRef
KEXTManagerCopyPersonalitiesForBundle(
KEXTManagerRef manager,
KEXTBundleRef bundle)
{
CFMutableArrayRef array;
CFArrayRef personKeys;
CFRange range;
void * context[2];
personKeys = _KEXTManagerGetPersonalityKeysForBundle(manager, bundle);
if ( !personKeys ) {
return NULL;
}
array = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if ( !array ) {
return NULL;
}
context[0] = manager;
context[1] = array;
range = CFRangeMake(0, CFArrayGetCount(personKeys));
CFArrayApplyFunction(personKeys, range, (CFArrayApplierFunction)ArrayCopyEntityForKey, context);
return array;
}
CFArrayRef
KEXTManagerCopyConfigsForBundle(
KEXTManagerRef manager,
KEXTBundleRef bundle)
{
CFMutableArrayRef array;
CFArrayRef configKeys;
CFRange range;
void * context[2];
configKeys = _KEXTManagerGetConfigKeysForBundle(manager, bundle);
if ( !configKeys ) {
return NULL;
}
array = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if ( !array ) {
return NULL;
}
context[0] = manager;
context[1] = array;
range = CFRangeMake(0, CFArrayGetCount(configKeys));
CFArrayApplyFunction(configKeys, range, (CFArrayApplierFunction)ArrayCopyEntityForKey, context);
return array;
}
static CFArrayRef
_KEXTBundleCopyModule (
CFDictionaryRef props )
{
CFArrayRef moduleArray;
CFDictionaryRef moduleDict;
CFDictionaryRef personalitiesDict;
moduleDict = CFDictionaryCreateMutableCopy(NULL, NULL, props);
if (!moduleDict) {
return NULL;
}
personalitiesDict = CFDictionaryGetValue(moduleDict, CFSTR("IOKitPersonalities"));
if (personalitiesDict) {
CFDictionaryRemoveValue(moduleDict, CFSTR("IOKitPersonalities"));
}
moduleArray = CFArrayCreate(kCFAllocatorDefault, &moduleDict, 1, &kCFTypeArrayCallBacks);
CFRelease(moduleDict);
return moduleArray; }
static void _personalityInjectName(
const void * key,
const void * val,
void * context)
{
CFStringRef * personalityName;
CFDictionaryRef * personality;
personalityName = (CFStringRef *)key;
personality = (CFDictionaryRef *)val;
CFDictionarySetValue(personality, CFSTR("IOPersonalityName"), personalityName);
return;
}
static CFArrayRef
_KEXTBundleCopyPersonalities (
CFDictionaryRef props )
{
CFDictionaryRef personalities;
CFDictionaryRef personsMutable;
CFArrayRef personalitiesArray;
CFIndex numPersonalities;
void ** personalityValues;
personalities = CFDictionaryGetValue(props, CFSTR(kPersonalitiesKey));
if ( ! personalities ) {
return NULL;
}
numPersonalities = CFDictionaryGetCount(personalities);
if (numPersonalities < 1) {
return NULL;
}
personsMutable = CFDictionaryCreateMutableCopy(NULL, 0, personalities);
if ( ! personsMutable ) {
return NULL;
}
CFDictionaryApplyFunction(personsMutable, & _personalityInjectName, NULL);
personalityValues = (void **)malloc(numPersonalities * sizeof(void *));
if (!personalityValues) {
return NULL;
}
CFDictionaryGetKeysAndValues(personsMutable, NULL, personalityValues);
personalitiesArray = CFArrayCreateMutable(kCFAllocatorDefault,
numPersonalities, &kCFTypeArrayCallBacks);
if (!personalitiesArray) {
return NULL;
}
CFArrayReplaceValues(personalitiesArray, CFRangeMake(0, 0),
personalityValues, numPersonalities);
free(personalityValues);
return personalitiesArray;
}
static void ArrayGetModuleAndKey(const void * val, void * context[])
{
CFMutableArrayRef keys;
CFMutableArrayRef mods;
CFStringRef bundleKey;
KEXTModuleRef mod;
bundleKey = context[0];
mods = context[1];
keys = context[2];
mod = KEXTModuleCreate(bundleKey, val);
if ( !mod ) {
return;
}
CFArrayAppendValue(mods, mod);
CFArrayAppendValue(keys, KEXTModuleGetPrimaryKey(mod));
CFRelease(mod);
}
static CFMutableArrayRef
_KEXTManagerCreateModulesArray(
CFStringRef bundleKey,
CFDictionaryRef props,
CFMutableArrayRef * keys,
Boolean isCFStyle )
{
CFMutableArrayRef modules;
CFMutableArrayRef modKeys;
CFArrayRef array;
CFRange range;
void * context[3];
if ( !props || !bundleKey || !keys )
return NULL;
array = _KEXTBundleCopyModule(props);
if ( !array ) {
return NULL;
}
modKeys = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
modules = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if ( !modules || !modKeys ) {
if ( modules ) {
CFRelease(modules);
}
if ( modKeys ) {
CFRelease(modKeys);
}
CFRelease(array);
return NULL;
}
context[0] = (void *)bundleKey;
context[1] = modules;
context[2] = modKeys;
range = CFRangeMake(0, CFArrayGetCount(array));
CFArrayApplyFunction(array, range, (CFArrayApplierFunction)ArrayGetModuleAndKey, context);
CFRelease(array);
*keys = modKeys;
return modules;
}
static void ArrayGetPersonalityAndKey(const void * val, void * context[])
{
CFMutableArrayRef personKeys;
CFMutableArrayRef persons;
CFStringRef bundleKey;
KEXTPersonalityRef person;
bundleKey = context[0];
persons = context[1];
personKeys = context[2];
person = KEXTPersonalityCreate(bundleKey, val);
if ( !person ) {
return;
}
CFArrayAppendValue(persons, person);
CFArrayAppendValue(personKeys, KEXTPersonalityGetPrimaryKey(person));
CFRelease(person);
}
static CFMutableArrayRef
_KEXTManagerCreatePersonsArray(
CFStringRef bundleKey,
CFDictionaryRef props,
CFMutableArrayRef * keys,
Boolean isCFStyle )
{
CFMutableArrayRef persons;
CFMutableArrayRef personKeys;
CFArrayRef array;
CFRange range;
void * context[3];
if ( !props || !bundleKey || !keys ) {
return NULL;
}
array = _KEXTBundleCopyPersonalities(props);
if ( !array ) {
return NULL;
}
personKeys = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
persons = CFArrayCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if ( !persons || !personKeys ) {
if ( persons ) {
CFRelease(persons);
}
if ( personKeys ) {
CFRelease(personKeys);
}
CFRelease(array);
return NULL;
}
context[0] = (void *)bundleKey;
context[1] = persons;
context[2] = personKeys;
range = CFRangeMake(0, CFArrayGetCount(array));
CFArrayApplyFunction(array, range, (CFArrayApplierFunction)ArrayGetPersonalityAndKey, context);
CFRelease(array);
*keys = personKeys;
return persons;
}
static KEXTReturn
_KEXTManagerCreateProperties(
KEXTManagerRef manager,
CFURLRef url,
CFDictionaryRef * properties,
Boolean * isCFStyle )
{
KEXTReturn ret;
CFStringRef urlString;
CFStringRef newPath;
CFStringRef str;
CFURLRef newUrl;
CFDataRef xmlData;
*isCFStyle = true;
urlString = CFURLGetString(url);
newPath = CFStringCreateWithFormat(
kCFAllocatorDefault,
NULL,
CFSTR("%@/Contents/Info.plist"),
urlString);
if ( !newPath ) {
return kKEXTReturnNoMemory;
}
newUrl = CFURLCreateWithString(kCFAllocatorDefault, newPath, NULL);
CFRelease(newPath);
if ( !newUrl ) {
return kKEXTReturnNoMemory;
}
ret = URLResourceCreateData(newUrl, &xmlData);
CFRelease(newUrl);
if ( ret != kKEXTReturnSuccess ) {
_KEXTManagerLogError(manager,
CFSTR("%@ is not a valid kernel extension bundle.\n"), urlString);
return kKEXTReturnNotKext;
}
if ( !xmlData ) {
_KEXTManagerLogError(manager,
CFSTR("%@ is not a valid kernel extension bundle.\n"), urlString);
return kKEXTReturnNotKext;
}
*properties = (CFDictionaryRef)CFPropertyListCreateFromXMLData(
kCFAllocatorDefault,
xmlData,
kCFPropertyListImmutable,
&str);
CFRelease(xmlData);
if ( !*properties ) {
KEXTError(kKEXTReturnSerializationError, CFSTR("Error obtaining property list"));
if ( str ) {
CFRelease(str);
}
return kKEXTReturnSerializationError;
}
if ( CFDictionaryGetTypeID() != CFGetTypeID(*properties) ) {
CFRelease(*properties);
*properties = NULL;
return kKEXTReturnError;
}
return kKEXTReturnSuccess;
}
static KEXTReturn
_KEXTManagerCreateEntities(
KEXTManagerRef manager,
CFURLRef url,
KEXTBundleRef * bundle,
CFArrayRef * modules,
CFArrayRef * persons )
{
KEXTReturn ret;
CFStringRef urlString;
CFStringRef bundleKey;
CFDateRef date;
CFDictionaryRef properties;
CFArrayRef keys;
Boolean isCFStyle;
if ( !url || !bundle || !modules || !persons ) {
return kKEXTReturnBadArgument;
}
urlString = CFURLGetString(url);
if (! _KEXTManagerIsKernelExtensionURL(url)) {
_KEXTManagerLogError(manager,
CFSTR("%@ is not a valid kernel extension bundle.\n"), urlString);
return kKEXTReturnNotKext;
}
ret = URLResourceExists(url);
if ( ret != kKEXTReturnSuccess ) {
return ret;
}
ret = URLResourceCreateModifcationTime(url, &date);
if ( ret != kKEXTReturnSuccess ) {
return ret;
}
ret = _KEXTManagerCreateProperties(manager, url, &properties, &isCFStyle);
if ( ret != kKEXTReturnSuccess) {
_KEXTManagerLogError(manager,
CFSTR("%@ is not a valid kernel extension bundle.\n"), urlString);
CFRelease(date);
return ret;
}
*bundle = KEXTBundleCreate(url, properties, isCFStyle);
if (!*bundle) {
CFRelease(properties);
CFRelease(date);
_KEXTManagerLogError(manager,
CFSTR("%@ is not a valid kernel extension bundle.\n"), urlString);
return kKEXTReturnNotKext;
}
bundleKey = KEXTBundleGetPrimaryKey(*bundle);
*modules = _KEXTManagerCreateModulesArray(bundleKey, properties, &keys, isCFStyle);
if ( *modules ) {
if ( keys ) {
CFRelease(keys);
}
CFDictionarySetValue(*bundle, CFSTR("BundleType"), CFSTR("KMOD"));
}
*persons = _KEXTManagerCreatePersonsArray(bundleKey, properties, &keys, isCFStyle);
if ( *persons ) {
if ( keys ) {
CFRelease(keys);
}
CFDictionarySetValue(*bundle, CFSTR("BundleType"), CFSTR("KEXT"));
}
CFDictionarySetValue(*bundle, CFSTR("ModificationDate"), date);
CFRelease(date);
return kKEXTReturnSuccess;
}
CFArrayRef
KEXTManagerCopyAllEntities(
KEXTManagerRef manager )
{
void ** vals;
CFArrayRef array;
CFIndex count;
count = CFDictionaryGetCount(deref(manager)->_entities);
vals = (void **)malloc(sizeof(void *) * count);
CFDictionaryGetKeysAndValues(deref(manager)->_entities, NULL, vals);
array = CFArrayCreate(kCFAllocatorDefault, vals, count, &kCFTypeArrayCallBacks);
free(vals);
return array;
}
CFArrayRef
KEXTManagerCopyAllBundles(
KEXTManagerRef manager )
{
CFDictionaryRef entities;
CFMutableArrayRef array;
if ( !manager ) {
return NULL;
}
entities = deref(manager)->_entities;
array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !array ) {
return NULL;
}
CFDictionaryApplyFunction(
entities,
(CFDictionaryApplierFunction)DictionaryCopyAllBundles,
array);
return array;
}
CFArrayRef
KEXTManagerCopyAllModules(
KEXTManagerRef manager )
{
CFDictionaryRef entities;
CFMutableArrayRef array;
if ( !manager ) {
return NULL;
}
entities = deref(manager)->_entities;
array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !array ) {
return NULL;
}
CFDictionaryApplyFunction(
entities,
(CFDictionaryApplierFunction)DictionaryCopyAllModules,
array);
return array;
}
CFArrayRef
KEXTManagerCopyAllPersonalities(
KEXTManagerRef manager )
{
CFDictionaryRef entities;
CFMutableArrayRef array;
if ( !manager ) {
return NULL;
}
entities = deref(manager)->_entities;
array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !array ) {
return NULL;
}
CFDictionaryApplyFunction(
entities,
(CFDictionaryApplierFunction)DictionaryCopyAllPersonalities,
array);
return array;
}
CFArrayRef
KEXTManagerCopyAllConfigs(
KEXTManagerRef manager )
{
CFDictionaryRef entities;
CFMutableArrayRef array;
if ( !manager ) {
return NULL;
}
entities = deref(manager)->_entities;
array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !array ) {
return NULL;
}
CFDictionaryApplyFunction(
entities,
(CFDictionaryApplierFunction)DictionaryCopyAllConfigs,
array);
return array;
}
void
KEXTManagerRemoveBundle(
KEXTManagerRef manager,
CFStringRef primaryKey )
{
KEXTManager * man = (KEXTManager *)manager;
KEXTBundleRef bundle;
if ( !manager || !primaryKey ) {
return;
}
bundle = _KEXTManagerGetEntityWithKey(manager, primaryKey);
if ( !bundle ) {
return;
}
if ( man->bcb.BundleWillRemove ) {
if ( !man->bcb.BundleWillRemove(manager, bundle, man->_context) )
return;
}
CFRetain(bundle);
_KEXTManagerRemoveBundleItemsOnly(manager, bundle);
if ( man->bcb.BundleWasRemoved ) {
man->bcb.BundleWasRemoved(manager, bundle, man->_context);
}
CFRelease(bundle);
}
static inline void
_KEXTManagerAddBundleAndContents(
KEXTManagerRef manager,
KEXTBundleRef bundle,
CFArrayRef modules,
CFArrayRef persons )
{
CFRange range;
_KEXTManagerAddBundleEntity(manager, bundle);
if ( modules ) {
range = CFRangeMake(0, CFArrayGetCount(modules));
CFArrayApplyFunction(
modules,
range,
(CFArrayApplierFunction)ArrayAddModuleEntities,
manager);
}
if ( persons ) {
range = CFRangeMake(0, CFArrayGetCount(persons));
CFArrayApplyFunction(
persons,
range,
(CFArrayApplierFunction)ArrayAddPersonalityEntities,
manager);
}
}
static void
_KEXTManagerRemoveBundleItemsOnly(
KEXTManagerRef manager,
KEXTBundleRef bundle )
{
CFStringRef primaryKey;
CFArrayRef array;
CFRange range;
primaryKey = KEXTBundleGetPrimaryKey(bundle);
if ( !primaryKey ) {
return;
}
array = KEXTManagerCopyModulesForBundle(manager, bundle);
if ( array ) {
range = CFRangeMake(0, CFArrayGetCount(array));
CFArrayApplyFunction(
array, range,
(CFArrayApplierFunction)ArrayRemoveModuleEntities,
manager);
}
array = KEXTManagerCopyPersonalitiesForBundle(manager, bundle);
if ( array ) {
range = CFRangeMake(0, CFArrayGetCount(array));
CFArrayApplyFunction(
array, range,
(CFArrayApplierFunction)ArrayRemovePersonalityEntities,
manager);
}
_KEXTManagerRemoveBundleEntity(manager, bundle);
}
KEXTReturn
KEXTManagerAddBundle(
KEXTManagerRef manager,
CFURLRef bundleUrl )
{
return _KEXTManagerAddBundle(manager, bundleUrl, true);
}
static KEXTReturn
_KEXTManagerAddBundle(
KEXTManagerRef manager,
CFURLRef bundleUrl,
Boolean toplevel)
{
KEXTBundleRef bundle;
KEXTReturn ret;
CFMutableArrayRef modules;
CFMutableArrayRef persons;
CFStringRef primaryKey;
if ( !manager || !bundleUrl ) {
return kKEXTReturnBadArgument;
}
ret = URLResourceExists(bundleUrl);
if ( ret != kKEXTReturnSuccess ) {
return ret;
}
ret = deref(manager)->bcb.BundleAuthentication(bundleUrl, deref(manager)->_context);
if ( ret != kKEXTReturnSuccess ) {
return ret;
}
ret = _KEXTManagerCreateEntities(manager, bundleUrl, &bundle, &modules, &persons);
if ( ret != kKEXTReturnSuccess ) {
return ret;
}
if ( deref(manager)->bcb.BundleWillAdd ) {
if ( !deref(manager)->bcb.BundleWillAdd(manager, bundle, deref(manager)->_context) ) {
return kKEXTReturnSuccess;
}
}
primaryKey = KEXTBundleGetPrimaryKey(bundle);
if ( !primaryKey ) {
return kKEXTReturnPropertyNotFound;
}
ret = kKEXTReturnSuccess;
do {
KEXTBundleRef bundle2;
bundle2 = _KEXTManagerGetEntityWithKey(manager, primaryKey);
if ( bundle2 ) {
CFStringRef info1;
CFStringRef info2;
info1 = KEXTBundleGetProperty(bundle, CFSTR("BundleInfo"));
info2 = KEXTBundleGetProperty(bundle2, CFSTR("BundleInfo"));
if ( (!info2 && !info1)
|| (info1 && info2 && CFEqual(info1, info2)) ) {
if ( deref(manager)->bcb.BundleError ) {
ret = deref(manager)->bcb.BundleError(
manager,
bundle,
kKEXTReturnBundleAlreadyExists,
deref(manager)->_context);
}
if ( ret != kKEXTReturnSuccess ) {
break;
}
}
_KEXTManagerRemoveBundleItemsOnly(manager, bundle2);
}
_KEXTManagerAddBundleAndContents(manager, bundle, modules, persons);
if ( deref(manager)->bcb.BundleWasAdded ) {
deref(manager)->bcb.BundleWasAdded(manager, bundle, deref(manager)->_context);
}
} while ( false );
if (toplevel) {
CFStringRef tmpStr;
CFURLRef pluginURL = 0;
tmpStr = KEXTBundleGetProperty(bundle, CFSTR("BundleFormat"));
if ( CFEqual(tmpStr, CFSTR("CF")) ) {
pluginURL = _KEXTBundleCreateFileURL(bundle,
CFSTR("PlugIns/"),
NULL);
}
if (pluginURL) {
(void) _KEXTManagerScanBundles(manager,
pluginURL,
false);
CFRelease(pluginURL);
}
}
if ( bundle )
CFRelease(bundle);
if ( modules )
CFRelease(modules);
if ( persons )
CFRelease(persons);
return ret;
}
CFIndex
KEXTManagerGetCount(
KEXTManagerRef manager )
{
return CFDictionaryGetCount(deref(manager)->_entities);
}
static void DictionaryRemoveBundleWithURL(void * key, void * val, void * context)
{
CFURLRef url;
KEXTManagerRef manager;
KEXTBundleRef bundle;
manager = context;
url = val;
if ( !val || !context ) {
return;
}
bundle = _KEXTManagerGetEntityWithKey(manager, val);
if ( bundle ) {
KEXTManagerRemoveBundle(manager, KEXTBundleGetPrimaryKey(bundle));
}
}
static KEXTReturn
_KEXTManagerScanBundles(
KEXTManagerRef manager,
CFURLRef url,
Boolean toplevel)
{
CFArrayRef array;
CFMutableArrayRef kextList;
CFMutableDictionaryRef urlRelCopy = 0;
CFIndex count;
CFIndex index;
SInt32 err;
array = (CFArrayRef)IOURLCreatePropertyFromResource(
kCFAllocatorDefault, url,
kIOURLFileDirectoryContents,
&err);
if ( !array )
return kKEXTReturnResourceNotFound;
kextList = CFArrayCreateMutable
(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
count = CFArrayGetCount(array);
for ( index = 0; index < count; index++ ) {
CFURLRef entry;
CFURLRef url;
CFStringRef path;
entry = CFArrayGetValueAtIndex(array, index);
if (!entry || !_KEXTManagerIsKernelExtensionURL(entry))
continue;
entry = CFURLCopyAbsoluteURL(entry);
path = CFURLGetString(entry);
url = CFURLCreateWithString(kCFAllocatorDefault, path, NULL);
CFRelease(entry);
CFArrayAppendValue(kextList, url);
CFRelease(url);
}
CFRelease(array); array = NULL;
urlRelCopy = CFDictionaryCreateMutableCopy
(kCFAllocatorDefault, 0, deref(manager)->_urlRels);
count = CFArrayGetCount(kextList);
for ( index = 0; index < count; index++ ) {
CFURLRef kextURL;
KEXTBundleRef bundle;
CFStringRef bundleKey;
kextURL = CFArrayGetValueAtIndex(kextList, index);
bundleKey = CFDictionaryGetValue(urlRelCopy, kextURL);
if ( !bundleKey ) {
_KEXTManagerAddBundle(manager, kextURL, toplevel);
}
else {
bundle = _KEXTManagerGetEntityWithKey(manager, bundleKey);
switch ( KEXTBundleValidate(bundle) ) {
case kKEXTBundleValidateRemoved:
KEXTManagerRemoveBundle(manager, bundleKey);
break;
case kKEXTBundleValidateModified:
_KEXTManagerRemoveBundleItemsOnly(manager, bundle);
_KEXTManagerAddBundle(manager, kextURL, toplevel);
break;
default:
break;
}
CFDictionaryRemoveValue(urlRelCopy, kextURL);
}
}
if (toplevel) {
CFDictionaryApplyFunction(urlRelCopy, (CFDictionaryApplierFunction)
DictionaryRemoveBundleWithURL, manager);
}
CFRelease(urlRelCopy);
CFRelease(kextList);
return kKEXTReturnSuccess;
}
KEXTReturn
KEXTManagerScanPath(
KEXTManagerRef manager,
CFURLRef url )
{
KEXTReturn error;
if ( !url || !CFURLHasDirectoryPath(url) ) {
return kKEXTReturnBadArgument;
}
error = kKEXTReturnSuccess;
do {
error = KEXTManagerScanConfigs(manager, url);
if ( (error != kKEXTReturnSuccess)
&& (error != kKEXTReturnResourceNotFound) ) {
printf("Error (%d): cannot get configs.\n", error);
}
error = _KEXTManagerScanBundles(manager, url, true);
if ( error != kKEXTReturnSuccess ) {
break;
}
} while ( false );
return error;
}
KEXTBundleRef
KEXTManagerGetBundle(
KEXTManagerRef manager,
CFStringRef primaryKey )
{
if ( !manager || !primaryKey ) {
return NULL;
}
return _KEXTManagerGetEntityWithKey(manager, primaryKey);
}
KEXTBundleRef
KEXTManagerGetBundleWithURL(
KEXTManagerRef manager,
CFURLRef url )
{
CFStringRef primaryKey;
if ( !manager || !url ) {
return NULL;
}
primaryKey = CFDictionaryGetValue(deref(manager)->_urlRels, url);
return KEXTManagerGetBundle(manager, primaryKey);
}
KEXTBundleRef
KEXTManagerGetBundleWithModule(
KEXTManagerRef manager,
CFStringRef moduleName )
{
KEXTModuleRef module;
CFStringRef bundleKey;
if ( !manager || !moduleName ) {
return NULL;
}
module = _KEXTManagerGetEntityWithKey(manager, moduleName);
if ( !module ) {
return NULL;
}
bundleKey = CFDictionaryGetValue(module, CFSTR("ParentKey"));
return _KEXTManagerGetEntityWithKey(manager, bundleKey);
}
KEXTModuleRef
KEXTManagerGetModule(
KEXTManagerRef manager,
CFStringRef moduleName)
{
KEXTModuleRef module;
CFStringRef primaryKey;
if ( !manager || !moduleName ) {
return NULL;
}
primaryKey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("KEXTModule?%@"), moduleName);
module = _KEXTManagerGetEntityWithKey(manager, primaryKey);
CFRelease(primaryKey);
return module;
}
KEXTPersonalityRef
KEXTManagerGetPersonality(
KEXTManagerRef manager,
CFStringRef primaryKey)
{
if ( !manager || !primaryKey ) {
return NULL;
}
return _KEXTManagerGetEntityWithKey(manager, primaryKey);
}
static Boolean _CFStringToVers(CFStringRef versionString, UInt32 * vers)
{
Boolean result = true;
char vers_buffer[32];
if (!CFStringGetCString(versionString,
vers_buffer, sizeof(vers_buffer) - 1, kCFStringEncodingMacRoman)) {
result = false;
goto finish;
}
if (!VERS_parse_string(vers_buffer, vers)) {
result = false;
goto finish;
}
finish:
return result;
}
static Boolean _KEXTManagerGetModuleVers(KEXTManagerRef manager,
KEXTModuleRef module,
CFStringRef versionKey,
UInt32 * vers)
{
Boolean result = true;
CFStringRef thisName = NULL;
CFStringRef thisVersion = NULL;
char vers_buffer[32];
thisName = KEXTModuleGetProperty(module, CFSTR(kNameKey));
if (!thisName) {
_KEXTManagerLogError(manager,
CFSTR("Extension has no \"CFBundleIdentifier\" property.\n"));
result = false;
goto finish;
}
thisVersion = KEXTModuleGetProperty(module, versionKey);
if (!thisVersion) {
_KEXTManagerLogError(manager,
CFSTR("Extension %@ has no \"%@\" property.\n"),
thisName, versionKey);
result = false;
goto finish;
}
if (!CFStringGetCString(thisVersion,
vers_buffer, sizeof(vers_buffer) - 1, kCFStringEncodingMacRoman)) {
_KEXTManagerLogError(manager,
CFSTR("Can't extract version for extension %@.\n"),
thisName);
result = false;
goto finish;
}
if (!VERS_parse_string(vers_buffer, vers)) {
_KEXTManagerLogError(manager,
CFSTR("Extension %@ has an invalid version string.\n"),
thisName);
result = false;
goto finish;
}
finish:
return result;
}
static KEXTReturn
_KEXTManagerGraphDependencies(
KEXTManagerRef manager,
KEXTModuleRef module,
CFStringRef requestedModuleName,
CFMutableArrayRef array )
{
KEXTReturn result = kKEXTReturnSuccess;
CFDictionaryRef dependencies = NULL; KEXTModuleRef mod = NULL; CFTypeID scratch = NULL; Boolean isKernelResource = false;
CFRange range;
CFIndex numDependencies = 0;
void ** nameList = NULL; void ** versionList = NULL; CFArrayRef nameArray = NULL; CFArrayRef versionArray = NULL; CFIndex i;
if ( !manager || !module || !array) {
result = kKEXTReturnBadArgument;
goto finish;
}
if (CFArrayGetCount(array) > 255) {
_KEXTManagerLogError(manager,
CFSTR("Dependency list for %@ is "
"ridiculously long (circular reference?).\n"),
requestedModuleName);
result = kKEXTReturnError;
goto finish;
}
scratch = KEXTModuleGetProperty(module, CFSTR("OSKernelResource"));
if ( scratch ) {
isKernelResource = CFBooleanGetValue(scratch);
}
if (isKernelResource) {
result = kKEXTReturnSuccess;
goto finish;
}
dependencies = KEXTModuleGetProperty(module, CFSTR(kRequiresKey));
if ( ! dependencies ) {
_KEXTManagerLogError(manager,
CFSTR("Extension %@ "
"declares no dependencies.\n"),
requestedModuleName);
#if 0
result = kKEXTReturnError;
goto finish;
#else
_KEXTManagerLogError(manager,
CFSTR("Loading anyway.\n"));
goto no_dependencies;
#endif 0
}
if (CFGetTypeID(dependencies) != CFDictionaryGetTypeID() ) {
result = kKEXTReturnError;
goto finish;
}
numDependencies = CFDictionaryGetCount(dependencies);
if (numDependencies < 1) {
goto no_dependencies;
}
nameList = (void **)malloc(numDependencies * sizeof(void *));
if (! nameList) {
result = kKEXTReturnNoMemory;
goto finish;
}
versionList = (void **)malloc(numDependencies * sizeof(void *));
if (! versionList) {
result = kKEXTReturnNoMemory;
goto finish;
}
CFDictionaryGetKeysAndValues(dependencies, nameList, versionList);
nameArray = CFArrayCreate(NULL, nameList, numDependencies,
&kCFTypeArrayCallBacks);
if (! nameArray) {
result = kKEXTReturnNoMemory;
goto finish;
}
versionArray = CFArrayCreate(NULL, versionList, numDependencies, &kCFTypeArrayCallBacks);
if (! versionArray) {
result = kKEXTReturnNoMemory;
goto finish;
}
for ( i = 0; i < numDependencies; i++ ) {
CFStringRef name;
CFStringRef version;
UInt32 req_vers;
UInt32 dep_vers;
UInt32 dep_compat_vers;
name = CFArrayGetValueAtIndex(nameArray, i);
if ( !name ) continue;
version = CFArrayGetValueAtIndex(versionArray, i);
if ( !version ) {
_KEXTManagerLogError(manager,
CFSTR("No required version for dependency %@ of extension %@.\n"),
name, requestedModuleName);
result = kKEXTReturnError;
goto finish;
}
if (!_CFStringToVers(version, &req_vers)) {
_KEXTManagerLogError(manager,
CFSTR("Can't parse required version for dependency %@ "
"of extension %@.\n"),
name, requestedModuleName);
result = kKEXTReturnError;
goto finish;
}
mod = KEXTManagerGetModule(manager, name);
if ( !mod ) {
_KEXTManagerLogError(manager,
CFSTR("Can't find dependency %@ of extension %@.\n"),
name, requestedModuleName);
result = kKEXTReturnMissingDependency;
goto finish;
}
if (!_KEXTManagerGetModuleVers(manager, mod,
CFSTR("CFBundleVersion"), &dep_vers)) {
_KEXTManagerLogError(manager,
CFSTR("Dependency %@ of extension %@ "
"declares no version.\n"),
name, requestedModuleName);
#if 0
result = kKEXTReturnError;
goto finish;
#else
_KEXTManagerLogError(manager,
CFSTR("Loading anyway.\n"));
#endif 0
}
if (!_KEXTManagerGetModuleVers(manager, mod,
CFSTR("OSBundleCompatibleVersion"),
&dep_compat_vers)) {
_KEXTManagerLogError(manager,
CFSTR("Dependency %@ of extension %@ "
"declares no compatible version.\n"),
name, requestedModuleName);
#if 0
result = kKEXTReturnError;
goto finish;
#else
_KEXTManagerLogError(manager,
CFSTR("Loading anyway.\n"));
#endif 0
}
if (req_vers > dep_vers || req_vers < dep_compat_vers) {
_KEXTManagerLogError(manager,
CFSTR("Installed version %@ of dependency %@ is not compatible "
"with extension %@.\n"),
version, name, requestedModuleName);
#if 0
result = kKEXTReturnDependencyVersionMismatch;
goto finish;
#else
_KEXTManagerLogError(manager,
CFSTR("Loading anyway.\n"));
#endif 0
}
range = CFRangeMake(0, CFArrayGetCount(array));
if ( !CFArrayContainsValue(array, range, mod)) {
result = _KEXTManagerGraphDependencies(manager, mod,
requestedModuleName, array);
if (result != kKEXTReturnSuccess) {
goto finish;
}
}
}
no_dependencies:
if ( ! isKernelResource ) {
if (numDependencies < 1) {
_KEXTManagerLogError(manager,
CFSTR("Extension %@ declares no dependencies.\n"),
requestedModuleName);
_KEXTManagerLogError(manager,
CFSTR("Loading anyway.\n"));
}
range = CFRangeMake(0, CFArrayGetCount(array));
if ( !CFArrayContainsValue(array, range, module) ) {
CFArrayAppendValue(array, module);
}
}
finish:
if (nameList) free(nameList);
if (versionList) free(versionList);
if (nameArray) CFRelease(nameArray);
if (versionArray) CFRelease(versionArray);
return result;
}
Boolean
KEXTManagerCopyModuleDependencies(
KEXTManagerRef manager,
KEXTModuleRef module,
CFArrayRef * array )
{
KEXTReturn graphDependencyResult;
CFStringRef moduleName;
CFMutableArrayRef modules;
Boolean ret;
if ( !manager || !module || !array ) {
return false;
}
moduleName = KEXTModuleGetProperty(module, CFSTR(kNameKey));
if ( !moduleName ) {
return false;
}
modules = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !modules ) {
return false;
}
graphDependencyResult = _KEXTManagerGraphDependencies(manager, module,
moduleName, modules);
if (graphDependencyResult == kKEXTReturnSuccess) {
ret = true;
} else {
ret = false;
}
*array = modules;
return ret;
}
KEXTReturn
KEXTManagerLoadModule(
KEXTManagerRef manager,
KEXTModuleRef module )
{
KEXTManager * man;
KEXTReturn graphDependencyResult;
CFStringRef moduleName;
CFMutableArrayRef array;
CFStringRef primaryKey;
CFStringRef mode;
CFIndex count;
CFIndex i;
KEXTReturn error;
if ( !manager || !module )
return kKEXTReturnBadArgument;
primaryKey = KEXTModuleGetPrimaryKey(module);
if ( !primaryKey ) {
return kKEXTReturnError;
}
moduleName = KEXTModuleGetProperty(module, CFSTR(kNameKey));
if ( !moduleName ) {
return kKEXTReturnError;
}
man = (KEXTManager *)manager;
mode = CFDictionaryGetValue(man->_noloads, primaryKey);
if ( mode && CFEqual(mode, CFSTR("Disabled")) ) {
return kKEXTReturnModuleDisabled;
}
if ( KEXTModuleIsLoaded(module, &error) ) {
if ( error == kKEXTReturnSuccess && man->mcb.ModuleError )
error = man->mcb.ModuleError(manager, module, kKEXTReturnModuleAlreadyLoaded, man->_context);
return error;
}
if (!KEXTManagerCheckSafeBootForModule(manager, module)) {
_KEXTManagerLogError(manager,
CFSTR("Extension %@ is not a safe-boot extension.\n"), moduleName);
return kKEXTReturnModuleDisabled;
}
array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !array ) {
return kKEXTReturnNoMemory;
}
graphDependencyResult = _KEXTManagerGraphDependencies(manager, module,
moduleName, array);
if (graphDependencyResult != kKEXTReturnSuccess) {
CFRelease(array);
return graphDependencyResult;
}
error = kKEXTReturnSuccess;
count = CFArrayGetCount(array);
for ( i = 0; i < count; i++ ) {
KEXTModuleRef mod1;
KEXTReturn err;
CFMutableArrayRef deps;
CFIndex j;
mod1 = (KEXTModuleRef)CFArrayGetValueAtIndex(array, i);
if ( !mod1 )
continue;
if ( KEXTModuleIsLoaded(mod1, &err) ) {
if ( man->mcb.ModuleError ) {
error = man->mcb.ModuleError(manager, mod1, kKEXTReturnModuleAlreadyLoaded, man->_context);
if ( (error != kKEXTReturnSuccess) &&
(error != kKEXTReturnModuleAlreadyLoaded) )
break;
}
continue;
}
if ( man->mcb.ModuleWillLoad ) {
if ( !man->mcb.ModuleWillLoad(manager, mod1, man->_context) )
continue;
}
deps = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
for ( j = 0; j < i; j++ ) {
KEXTModuleRef dep;
dep = (KEXTModuleRef)CFArrayGetValueAtIndex(array, j);
CFArrayAppendValue(deps, dep);
}
error = _KEXTManagerLoadModule(manager, mod1, deps);
CFRelease(deps);
if ( (error != kKEXTReturnSuccess) && man->mcb.ModuleError ) {
error = man->mcb.ModuleError(manager, mod1, error, man->_context);
}
if ( error != kKEXTReturnSuccess )
break;
if ( man->mcb.ModuleWasLoaded ) {
man->mcb.ModuleWasLoaded(manager, mod1, man->_context);
}
}
CFRelease(array);
return error;
}
KEXTReturn
KEXTManagerUnloadModule(
KEXTManagerRef manager,
KEXTModuleRef module )
{
KEXTReturn ret;
CFStringRef modName;
kern_return_t status;
char name[256];
ret = kKEXTReturnError;
if ( !manager || !module )
return kKEXTReturnBadArgument;
modName = KEXTModuleGetProperty(module, CFSTR(kNameKey));
if ( !modName || !CFStringGetCString(modName, name, 256, kCFStringEncodingMacRoman) ) {
return kKEXTReturnError;
}
if ( deref(manager)->mcb.ModuleWillUnload ) {
if ( !deref(manager)->mcb.ModuleWillUnload(manager, module, deref(manager)->_context) ) {
return kKEXTReturnSuccess;
}
}
status = IOCatalogueTerminate(deref(manager)->_catPort, kIOCatalogModuleUnload, name);
ret = KERN2KEXTReturn(status);
if ( (ret != kKEXTReturnSuccess) &&
deref(manager)->mcb.ModuleError ) {
ret = deref(manager)->mcb.ModuleError(manager, module, ret, deref(manager)->_context);
}
if ( (ret == kKEXTReturnSuccess ) &&
deref(manager)->mcb.ModuleWasUnloaded ) {
deref(manager)->mcb.ModuleWasUnloaded(manager, module, deref(manager)->_context);
}
return ret;
}
static void ArrayPersonalityWillLoad(const void * val, void * context[])
{
KEXTManagerRef manager;
KEXTPersonalityRef personality;
CFMutableArrayRef toload;
Boolean boolval;
personality = (KEXTPersonalityRef)val;
manager = context[0];
toload = context[1];
boolval = true;
if ( deref(manager)->pcb.PersonalityWillLoad ) {
boolval = deref(manager)->pcb.PersonalityWillLoad(
manager,
personality,
deref(manager)->_context);
}
if ( true ) {
CFArrayAppendValue(toload, personality);
}
}
static void ArrayPersonalityCollectProperties(const void * val, void * context)
{
KEXTPersonalityRef person;
CFDictionaryRef props;
CFMutableArrayRef properties;
person = (KEXTPersonalityRef)val;
properties = context;
props = CFDictionaryGetValue(person, CFSTR("PersonProperties"));
if ( props ) {
CFArrayAppendValue(properties, props);
}
}
static void ArrayPersonalityPostamble(const void * val, void * context[])
{
KEXTManagerRef manager;
KEXTPersonalityRef person;
KEXTReturn error;
person = (KEXTPersonalityRef)val;
manager = context[0];
error = *(KEXTReturn *)context[1];
if ( (error != kKEXTReturnSuccess) &&
deref(manager)->pcb.PersonalityError ) {
error = deref(manager)->pcb.PersonalityError(
manager,
person,
error,
deref(manager)->_context);
}
if ( error != kKEXTReturnSuccess ) {
return;
}
if ( deref(manager)->pcb.PersonalityWasLoaded ) {
deref(manager)->pcb.PersonalityWasLoaded(
manager,
person,
deref(manager)->_context);
}
}
KEXTReturn
KEXTManagerLoadPersonalities(
KEXTManagerRef manager,
CFArrayRef personalities )
{
CFMutableArrayRef toload;
CFMutableArrayRef properties;
CFRange range;
KEXTReturn error;
void * context[2];
if ( !manager || !personalities ) {
return kKEXTReturnBadArgument;
}
toload = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !toload ) {
return kKEXTReturnNoMemory;
}
properties = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !properties ) {
CFRelease(toload);
return kKEXTReturnNoMemory;
}
context[0] = manager;
context[1] = toload;
range = CFRangeMake(0, CFArrayGetCount(personalities));
CFArrayApplyFunction(personalities,
range,
(CFArrayApplierFunction)ArrayPersonalityWillLoad,
context);
if ( CFArrayGetCount(personalities) < 1 ) {
return kKEXTReturnSuccess;
}
range = CFRangeMake(0, CFArrayGetCount(toload));
CFArrayApplyFunction(toload,
range,
(CFArrayApplierFunction)ArrayPersonalityCollectProperties,
properties);
error = KEXTSendDataToCatalog(deref(manager)->_catPort, kIOCatalogAddDrivers, properties);
CFRelease(properties);
context[0] = manager;
context[1] = &error;
CFArrayApplyFunction(toload,
range,
(CFArrayApplierFunction)ArrayPersonalityPostamble,
context);
CFRelease(toload);
return error;
}
KEXTReturn
KEXTManagerUnloadPersonality(
KEXTManagerRef manager,
KEXTPersonalityRef personality )
{
KEXTReturn error;
if ( !manager || !personality ) {
return kKEXTReturnBadArgument;
}
if ( deref(manager)->pcb.PersonalityWillUnload ) {
if ( !deref(manager)->pcb.PersonalityWillUnload(manager, personality, deref(manager)->_context) ) {
return kKEXTReturnSuccess;
}
}
error = _KEXTManagerUnloadPersonality(manager, personality);
if ( (error != kKEXTReturnSuccess) &&
deref(manager)->pcb.PersonalityError ) {
error = deref(manager)->pcb.PersonalityError(manager, personality, error, deref(manager)->_context);
}
if ( (error == kKEXTReturnSuccess) &&
deref(manager)->pcb.PersonalityWasUnloaded ) {
deref(manager)->pcb.PersonalityWasUnloaded(manager, personality, deref(manager)->_context);
}
return error;
}
KEXTReturn
KEXTManagerTerminatePersonality(
KEXTManagerRef manager,
KEXTPersonalityRef personality )
{
kern_return_t status;
KEXTReturn ret;
CFStringRef str;
char name[256];
ret = kKEXTReturnError;
if ( !manager || !personality ) {
return kKEXTReturnBadArgument;
}
str = KEXTPersonalityGetProperty(personality, CFSTR("IOClass"));
if ( str ) {
if ( !CFStringGetCString(str, name, 256, kCFStringEncodingMacRoman) ) {
return kKEXTReturnError;
}
status = IOCatalogueTerminate(
deref(manager)->_catPort,
kIOCatalogServiceTerminate,
name);
ret = KERN2KEXTReturn(status);
}
else {
ret = kKEXTReturnPropertyNotFound;
}
return ret;
}
CFStringRef
KEXTManagerGetEntityType(
KEXTEntityRef entity)
{
if ( !entity ) {
return NULL;
}
return CFDictionaryGetValue(entity, CFSTR("EntityType"));
}
mach_port_t
_KEXTManagerGetMachPort(
KEXTManagerRef manager )
{
return deref(manager)->_catPort;
}
static void logCFString(void (*logFunc)(const char *),
CFStringRef format,
va_list arguments)
{
CFStringRef string = 0;
unsigned stringLength;
unsigned bufferLength;
char * buffer = NULL;
string = CFStringCreateWithFormatAndArguments(
NULL, NULL, format, arguments);
if (!string) return;
stringLength = CFStringGetLength(string);
bufferLength = (1 + stringLength) * sizeof(char);
buffer = (char *)malloc(bufferLength);
if (!buffer) return;
if (!CFStringGetCString(string, buffer, bufferLength,
kCFStringEncodingMacRoman)) {
goto finish;
}
logFunc(buffer);
finish:
if (buffer) free(buffer);
if (string) CFRelease(string);
return;
}
static void _KEXTManagerLogError(KEXTManagerRef manager,
CFStringRef format, ...)
{
KEXTManager * mgr = (KEXTManager *)manager;
va_list args;
if (!mgr->_logErrorFunc) return;
va_start(args, format);
logCFString(mgr->_logErrorFunc, format, args);
va_end(args);
return;
}
static void _KEXTManagerLogMessage(KEXTManagerRef manager,
CFStringRef format, ...)
{
KEXTManager * mgr = (KEXTManager *)manager;
va_list args;
if (!mgr->_logMessageFunc) return;
va_start(args, format);
logCFString(mgr->_logMessageFunc, format, args);
va_end(args);
return;
}
void
_KEXTManagerShow(
KEXTManagerRef manager )
{
printf("entities:");CFShow(deref(manager)->_entities);
printf("modules:");CFShow(deref(manager)->_modRels);
printf("persons:");CFShow(deref(manager)->_perRels);
printf("urls :");CFShow(deref(manager)->_urlRels);
printf("configs:");CFShow(deref(manager)->_cfgRels);
printf("noloads:");CFShow(deref(manager)->_noloads);
printf("date :");CFShow(deref(manager)->_configsDate);
}
static void CopyNoLoads(const void * key, const void * val, void * context)
{
CFMutableArrayRef array;
CFDictionaryRef dict;
const void * keys[2];
const void * vals[2];
if ( !val || !key ) {
return;
}
array = context;
keys[0] = CFSTR("PrimaryKey"); vals[0] = key;
keys[1] = CFSTR("LoadValue"); vals[1] = val;
dict = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFArrayAppendValue(array, dict);
CFRelease(dict);
}
KEXTReturn
KEXTManagerSaveConfigs(
KEXTManagerRef manager,
CFURLRef url )
{
CFArrayRef array;
CFMutableArrayRef noloads;
CFDictionaryRef dict;
CFDataRef data;
CFURLRef path;
SInt32 error;
KEXTReturn ret;
const void * vals[2];
const void * keys[2];
if ( !manager || !url ) {
return kKEXTReturnBadArgument;
}
array = KEXTManagerCopyAllConfigs(manager);
if ( !array ) {
return kKEXTReturnNoMemory;
}
noloads = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( !noloads ) {
CFRelease(array);
return kKEXTReturnNoMemory;
}
CFDictionaryApplyFunction(deref(manager)->_noloads, (CFDictionaryApplierFunction)CopyNoLoads, noloads);
if ( (CFArrayGetCount(array) < 1) &&
(CFArrayGetCount(noloads) < 1) ) {
CFRelease(array);
CFRelease(noloads);
return kKEXTReturnSuccess;
}
keys[0] = CFSTR("Configs"); vals[0] = array;
keys[1] = CFSTR("Modules"); vals[1] = noloads;
dict = CFDictionaryCreate(kCFAllocatorDefault, keys, vals, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(array);
CFRelease(noloads);
if ( !dict ) {
return kKEXTReturnNoMemory;
}
if ( deref(manager)->_mode == kKEXTManagerDefaultMode ) {
#warning finish me.
}
data = CFPropertyListCreateXMLData(kCFAllocatorDefault, dict);
CFRelease(dict);
if ( !data ) {
return kKEXTReturnNoMemory;
}
ret = kKEXTReturnSuccess;
do {
path = CFURLCreateCopyAppendingPathComponent(
kCFAllocatorDefault,
url,
CFSTR("Configuration.current"),
false);
if ( !path ) {
ret = kKEXTReturnNoMemory;
break;
}
ret = IOURLWriteDataAndPropertiesToResource(path, data, NULL, &error);
CFRelease(path);
if ( ret != kKEXTReturnSuccess ) {
break;
}
} while ( false );
CFRelease(data);
return ret;
}
static void RemoveEntitiesWithConfig(const void * val, void * context)
{
KEXTConfigRef config1;
KEXTConfigRef config2;
CFMutableDictionaryRef dict;
CFStringRef primaryKey;
config1 = (KEXTConfigRef)val;
dict = context;
primaryKey = KEXTPersonalityGetPrimaryKey(config1);
if ( !primaryKey ) {
return;
}
config2 = (KEXTConfigRef)CFDictionaryGetValue(dict, primaryKey);
if ( !config2 ) {
return;
}
if ( !CFEqual(config1, config2) ) {
return;
}
CFDictionaryRemoveValue(dict, primaryKey);
}
static void ArrayRemoveConfigsWithKey(const void * val, void * context)
{
KEXTManagerRef manager;
KEXTConfigRef config;
if ( !val || !context ) {
return;
}
manager = context;
config = KEXTManagerGetConfig(manager, val);
if ( config ) {
_KEXTManagerRemoveConfigEntityWithCallback(manager, config);
}
}
static void DictionaryRemoveFromConfigs(const void * key, const void * val, void * context)
{
CFArrayRef configKeys;
configKeys = (CFArrayRef)val;
if ( configKeys ) {
CFRange range;
range = CFRangeMake(0, CFArrayGetCount(configKeys));
CFArrayApplyFunction(configKeys, range, ArrayRemoveConfigsWithKey, context);
}
}
static void
_KEXTManagerRemoveMissingConfigs(
KEXTManagerRef manager,
CFArrayRef configs )
{
CFMutableDictionaryRef dict;
CFRange range;
if ( !manager || !deref(manager)->_cfgRels || !configs ) {
return;
}
dict = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, deref(manager)->_cfgRels);
if ( !dict ) {
return;
}
range = CFRangeMake(0, CFArrayGetCount(configs));
CFArrayApplyFunction(configs, range, RemoveEntitiesWithConfig, dict);
CFDictionaryApplyFunction(dict, DictionaryRemoveFromConfigs, manager);
CFRelease(dict);
}
static void ArrayAddConfigEntityAndSignal(void * val, void * context)
{
KEXTManagerRef manager;
KEXTConfigRef config;
manager = context;
config = val;
KEXTManagerAddConfig(manager, config);
}
static void
_KEXTManagerAddNewConfigs(
KEXTManagerRef manager,
CFArrayRef configs )
{
CFRange range;
if ( !manager || !configs ) {
return;
}
range = CFRangeMake(0, CFArrayGetCount(configs));
CFArrayApplyFunction(configs, range, (CFArrayApplierFunction)ArrayAddConfigEntityAndSignal, manager);
}
static void AddNoLoads(void * val, void * context)
{
CFMutableDictionaryRef noloads;
CFDictionaryRef modconf;
CFStringRef primaryKey;
CFStringRef loadValue;
noloads = context;
modconf = val;
primaryKey = CFDictionaryGetValue(modconf, CFSTR("PrimaryKey"));
loadValue = CFDictionaryGetValue(modconf, CFSTR("LoadValue"));
CFDictionarySetValue(noloads, primaryKey, loadValue);
}
KEXTReturn
KEXTManagerScanConfigs(
KEXTManagerRef manager,
CFURLRef url )
{
CFDateRef date;
CFDataRef data;
CFStringRef path;
CFStringRef tail;
CFStringRef str;
CFURLRef newUrl;
CFDictionaryRef dict;
CFArrayRef configs;
CFArrayRef noloads;
KEXTReturn error;
SInt32 cferr;
if ( !manager ) {
return kKEXTReturnBadArgument;
}
switch ( deref(manager)->_mode ) {
case kKEXTManagerInstallMode:
tail = CFSTR("install");
break;
case kKEXTManagerRecoveryMode:
tail = CFSTR("previous");
break;
case kKEXTManagerDefaultMode:
tail = CFSTR("current");
break;
default:
tail = NULL;
break;
}
if ( !tail ) {
return kKEXTReturnBadArgument;
}
path = CFURLGetString(url);
path = CFStringCreateWithFormat(
kCFAllocatorDefault,
NULL,
CFSTR("%@/Configuration.%@"),
path,
tail);
if ( !path ) {
return kKEXTReturnNoMemory;
}
newUrl = CFURLCreateWithString(
kCFAllocatorDefault,
path,
NULL);
CFRelease(path);
if ( !newUrl ) {
return kKEXTReturnNoMemory;
}
error = KEXTManagerAuthenticateURL(newUrl);
if ( (error != kKEXTReturnSuccess) ) {
CFRelease(newUrl);
return error;
}
date = IOURLCreatePropertyFromResource(
kCFAllocatorDefault,
url,
kIOURLFileLastModificationTime,
&cferr);
if ( !date ) {
CFRelease(newUrl);
return kKEXTReturnError;
}
if ( deref(manager)->_configsDate ) {
if ( CFEqual(deref(manager)->_configsDate, date) ) {
CFRelease(date);
return kKEXTReturnSuccess;
}
CFRelease(deref(manager)->_configsDate);
deref(manager)->_configsDate = NULL;
}
deref(manager)->_configsDate = date;
error = URLResourceCreateData(newUrl, &data);
CFRelease(newUrl);
if ( error != kKEXTReturnSuccess ) {
return error;
}
dict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(
kCFAllocatorDefault,
data,
kCFPropertyListMutableContainersAndLeaves,
&str);
CFRelease(data);
if ( !dict ) {
if ( deref(manager)->_configsDate ) {
CFRelease(deref(manager)->_configsDate);
deref(manager)->_configsDate = NULL;
}
if ( str ) {
CFRelease(str);
}
return kKEXTReturnSerializationError;
}
configs = CFDictionaryGetValue(dict, CFSTR("Configs"));
if ( configs ) {
_KEXTManagerRemoveMissingConfigs(manager, configs);
_KEXTManagerAddNewConfigs(manager, configs);
}
noloads = CFDictionaryGetValue(dict, CFSTR("Modules"));
if ( noloads ) {
CFRange range;
CFDictionaryRemoveAllValues(deref(manager)->_noloads);
range = CFRangeMake(0, CFArrayGetCount(noloads));
CFArrayApplyFunction(noloads, range, (CFArrayApplierFunction)AddNoLoads, deref(manager)->_noloads);
}
CFRelease(dict);
return kKEXTReturnSuccess;
}
KEXTConfigRef
KEXTManagerCreateConfig(
KEXTManagerRef manager,
KEXTPersonalityRef personality )
{
KEXTPersonalityRef config;
CFDictionaryRef props;
CFMutableDictionaryRef properties;
Boolean found;
if ( !manager || !personality ) {
return NULL;
}
found = false;
config = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, personality);
props = CFDictionaryGetValue(config, CFSTR("PersonProps"));
if ( props ) {
properties = CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 0, props);
CFDictionarySetValue(config, CFSTR("PersonProps"), properties);
CFRelease(properties);
}
if ( config ) {
CFStringRef key;
CFStringRef newKey;
CFIndex index;
key = CFDictionaryGetValue(config, CFSTR("PrimaryKey"));
found = false;
for ( index = 0; index < 0xffff; index++ ) {
newKey = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@?%x"), key, index);
if ( !CFDictionaryGetValue(deref(manager)->_entities, newKey) ) {
CFMutableDictionaryRef dict;
CFStringRef name;
CFStringRef newName;
CFNumberRef score;
CFIndex num;
dict = (CFMutableDictionaryRef)CFDictionaryGetValue(config, CFSTR("PersonProperties"));
CFDictionarySetValue(config, CFSTR("IsConfig"), kCFBooleanTrue);
CFDictionarySetValue(config, CFSTR("PrimaryKey"), newKey);
if ( !dict ) {
break;
}
name = CFDictionaryGetValue(dict, CFSTR("Name"));
if ( name ) {
newName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@?%x"), name, index);
CFDictionarySetValue(dict, CFSTR("Name"), newName);
CFRelease(newName);
}
num = 0;
score = KEXTPersonalityGetProperty(personality, CFSTR("IOProbeScore"));
if ( score ) {
CFNumberGetValue(score, kCFNumberSInt32Type, &num);
}
num += 10;
score = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &num);
if ( score ) {
CFDictionarySetValue(dict, CFSTR("IOProbeScore"), score);
CFRelease(score);
}
CFRelease(newKey);
found = true;
break;
}
CFRelease(newKey);
}
}
if ( !found && config ) {
CFRelease(config);
config = NULL;
}
return config;
}
void
KEXTManagerAddConfig(
KEXTManagerRef manager,
KEXTConfigRef config )
{
Boolean ret;
if ( !manager || !config ) {
return;
}
ret = true;
if ( deref(manager)->ccb.ConfigWillAdd ) {
ret = deref(manager)->ccb.ConfigWillAdd(manager, config, deref(manager)->_context);
}
if ( !ret ) {
return;
}
_KEXTManagerAddConfigEntity(manager, config);
if ( deref(manager)->ccb.ConfigWasAdded ) {
deref(manager)->ccb.ConfigWasAdded(manager, config, deref(manager)->_context);
}
}
void
_KEXTManagerRemoveConfigEntityWithCallback(
KEXTManagerRef manager,
KEXTConfigRef config )
{
Boolean ret;
ret = true;
if ( deref(manager)->ccb.ConfigWillRemove ) {
ret = deref(manager)->ccb.ConfigWillRemove(manager, config, deref(manager)->_context);
}
if ( !ret ) {
return;
}
CFRetain(config);
_KEXTManagerRemoveConfigEntity(manager, config);
if ( deref(manager)->ccb.ConfigWasRemoved ) {
deref(manager)->ccb.ConfigWasRemoved(manager, config, deref(manager)->_context);
}
CFRelease(config);
}
KEXTConfigRef
KEXTManagerGetConfig(
KEXTManagerRef manager,
CFStringRef primaryKey )
{
return _KEXTManagerGetEntityWithKey(manager, primaryKey);
}
void
KEXTManagerRemoveConfig(
KEXTManagerRef manager,
CFStringRef primaryKey )
{
KEXTConfigRef config;
if ( !manager || !primaryKey ) {
return;
}
config = KEXTManagerGetConfig(manager, primaryKey);
if ( config ) {
_KEXTManagerRemoveConfigEntityWithCallback(manager, config);
}
}
static void ArrayRemoveConfigEntityWithCallback(void * val, void * context)
{
KEXTManagerRef manager;
KEXTConfigRef config;
if ( !val || !context ) {
return;
}
manager = context;
config = val;
_KEXTManagerRemoveConfigEntityWithCallback(manager, config);
}
void
KEXTManagerRemoveConfigsForBundle(
KEXTManagerRef manager,
KEXTBundleRef bundle )
{
CFArrayRef array;
array = KEXTManagerCopyConfigsForBundle(manager, bundle);
if ( array ) {
CFRange range;
range = CFRangeMake(0, CFArrayGetCount(array));
CFArrayApplyFunction(array, range, (CFArrayApplierFunction)ArrayRemoveConfigEntityWithCallback, manager);
CFRelease(array);
}
}
void
KEXTManagerSetModuleMode(
KEXTManagerRef manager,
KEXTModuleRef module,
KEXTModuleMode mode )
{
CFMutableDictionaryRef noloads;
CFStringRef primaryKey;
CFStringRef val;
if ( !manager || !module ) {
return;
}
noloads = deref(manager)->_noloads;
primaryKey = KEXTModuleGetPrimaryKey(module);
switch ( mode ) {
case kKEXTModuleModeDefault: {
val = CFDictionaryGetValue(noloads, primaryKey);
if ( val ) {
CFDictionaryRemoveValue(noloads, primaryKey);
}
}
break;
case kKEXTModuleModeNoload: {
CFDictionarySetValue(noloads, primaryKey, CFSTR("Disabled"));
}
break;
case kKEXTModuleModeForceLoad: {
CFDictionarySetValue(noloads, primaryKey, CFSTR("Force"));
}
break;
}
}