CLDAPv3Configs.cpp [plain text]
#include "CLDAPv3Configs.h"
#include "CLog.h"
#include "CLDAPPlugInPrefs.h"
#include "CLDAPNodeConfig.h"
#include "CLDAPConnection.h"
#include "BaseDirectoryPlugin.h"
#include "CCachePlugin.h"
#include <DirectoryServiceCore/DSUtils.h>
#include <DirectoryService/DirServicesPriv.h>
#include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
#include <unistd.h>
#include <sys/stat.h> //used for mkdir and stat
#include <syslog.h> //error logging
extern bool gServerOS;
extern bool gDHCPLDAPEnabled;
extern CFRunLoopRef gPluginRunLoop;
extern CCachePlugin *gCacheNode;
extern dsBool gDSInstallDaemonMode;
extern dsBool gDSLocalOnlyMode;
extern dsBool gDSDebugMode;
#pragma mark -
#pragma mark CLDAPv3Configs Class
CLDAPv3Configs::CLDAPv3Configs( UInt32 inSignature ) :
fNodeConfigMapMutex("CLDAPv3Configs::fNodeConfigMapMutex"), fXMLConfigLock("CLDAPv3Configs::fXMLConfigLock")
{
fPlugInSignature = inSignature;
fDHCPLDAPServers = NULL;
fNodeRegistrationEvent.ResetEvent();
CFStringRef key = CFSTR(kDSStdNotifyDHCPConfigStateChanged);
bool bWatching = false;
SCDynamicStoreContext scContext = { 0, this, NULL, NULL, NULL };
CFArrayRef notifyKeys = CFArrayCreate( kCFAllocatorDefault, (const void **)&key, 1, &kCFTypeArrayCallBacks );
SCDynamicStoreRef store = SCDynamicStoreCreate( kCFAllocatorDefault, CFSTR("CLDAPv3Configs::CLDAPv3Configs"), DHCPLDAPConfigNotification,
&scContext );
if ( store != NULL && notifyKeys != NULL )
{
SCDynamicStoreSetNotificationKeys( store, notifyKeys, NULL );
CFRunLoopSourceRef rls = SCDynamicStoreCreateRunLoopSource( kCFAllocatorDefault, store, 0 );
if ( rls != NULL )
{
CFRunLoopAddSource( gPluginRunLoop, rls, kCFRunLoopDefaultMode );
bWatching = true;
}
}
if ( bWatching )
DbgLog( kLogPlugin, "CLDAPv3Configs::CLDAPv3Configs - is now watching for DHCP LDAP configuration changes from Search Node" );
else
syslog( LOG_ALERT, "LDAPv3 - was unable to watch for DHCP LDAP configuration changes from Search Node" );
DSCFRelease( notifyKeys );
DSCFRelease( store );
}
CLDAPv3Configs::~CLDAPv3Configs ( void )
{
fNodeConfigMapMutex.WaitLock();
for ( LDAPNodeConfigMapI configIter = fNodeConfigMap.begin(); configIter != fNodeConfigMap.end(); configIter++ )
DSRelease( configIter->second );
fNodeConfigMap.clear();
fNodeConfigMapMutex.SignalLock();
}
#pragma mark -
#pragma mark Node registrations
void CLDAPv3Configs::RegisterAllNodes( void )
{
static pthread_mutex_t onlyOneAtTime = PTHREAD_MUTEX_INITIALIZER;
if ( pthread_mutex_trylock(&onlyOneAtTime) == 0 )
{
fNodeRegistrationEvent.ResetEvent();
CFDataRef xmlData = NULL;
if ( ReadXMLConfig(&xmlData) == eDSNoErr )
InitializeWithXML( xmlData );
DSCFRelease( xmlData );
if ( gDSInstallDaemonMode == false && gDSLocalOnlyMode == false && gDSDebugMode == false )
dsPostNodeEvent();
fNodeRegistrationEvent.PostEvent();
pthread_mutex_unlock( &onlyOneAtTime );
}
}
void CLDAPv3Configs::UnregisterAllNodes( void )
{
fNodeConfigMapMutex.WaitLock();
for ( LDAPNodeConfigMapI iter = fNodeConfigMap.begin(); iter != fNodeConfigMap.end(); iter++ )
{
tDataListPtr ldapName = dsBuildListFromStringsPriv( "LDAPv3", iter->first.c_str(), NULL );
if ( ldapName != NULL )
{
CServerPlugin::_UnregisterNode( fPlugInSignature, ldapName );
dsDataListDeallocatePriv( ldapName );
DSFree( ldapName );
}
}
if ( gDSInstallDaemonMode == false && gDSLocalOnlyMode == false && gDSDebugMode == false )
dsPostNodeEvent();
fNodeConfigMapMutex.SignalLock();
}
#pragma mark -
#pragma mark Reading or Updating current config
CFDataRef CLDAPv3Configs::CopyLiveXMLConfig( void )
{
CFDataRef combinedConfigDataRef = NULL;
CFMutableDictionaryRef configDict = NULL;
CFMutableArrayRef dhcpConfigArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFDataRef configXML = NULL;
fXMLConfigLock.WaitLock();
fNodeConfigMapMutex.WaitLock();
if ( ReadXMLConfig(&configXML) == eDSNoErr )
{
configDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
configXML,
kCFPropertyListMutableContainersAndLeaves,
NULL );
if ( configDict != NULL )
{
for ( LDAPNodeConfigMapI configIter = fNodeConfigMap.begin(); configIter != fNodeConfigMap.end(); configIter++ )
{
CLDAPNodeConfig *pConfig = configIter->second;
if ( pConfig->fDHCPLDAPServer == true )
{
CFDictionaryRef curConfigDict = pConfig->GetConfiguration();
if ( curConfigDict != NULL )
{
CFArrayAppendValue( dhcpConfigArray, curConfigDict );
DSCFRelease( curConfigDict );
}
}
}
}
}
fNodeConfigMapMutex.SignalLock();
fXMLConfigLock.SignalLock();
if ( CFArrayGetCount(dhcpConfigArray) > 0 )
CFDictionaryAddValue( configDict, CFSTR(kXMLDHCPConfigArrayKey), dhcpConfigArray );
combinedConfigDataRef = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict );
DSCFRelease( configXML );
DSCFRelease( dhcpConfigArray );
DSCFRelease( configDict );
return combinedConfigDataRef;
}
char **CLDAPv3Configs::GetDHCPBasedLDAPNodes( UInt32 *outCount )
{
UInt32 counter = 0;
CLDAPNodeConfig *pConfig = NULL;
char **outList = NULL;
fNodeConfigMapMutex.WaitLock();
for ( LDAPNodeConfigMapI configIter = fNodeConfigMap.begin(); configIter != fNodeConfigMap.end(); configIter++ )
{
if ( configIter->second->fDHCPLDAPServer == true )
counter++;
}
(*outCount) = counter;
if ( counter > 0 )
{
outList = (char **) calloc( counter + 1, sizeof(char*) );
counter = 0;
for ( LDAPNodeConfigMapI configIter = fNodeConfigMap.begin(); configIter != fNodeConfigMap.end(); configIter++ )
{
pConfig = configIter->second;
if ( pConfig->fDHCPLDAPServer == true )
{
char *theDHCPNodeName = (char *) calloc( 1, sizeof(kLDAPv3Str) + strlen(pConfig->fNodeName) );
strcpy( theDHCPNodeName, kLDAPv3Str );
strcat( theDHCPNodeName, pConfig->fNodeName );
outList[counter] = theDHCPNodeName;
counter++;
}
}
}
fNodeConfigMapMutex.SignalLock();
return outList;
}
SInt32 CLDAPv3Configs::NewXMLConfig( CFDataRef inXMLData )
{
if ( inXMLData != NULL )
{
CFRetain( inXMLData );
if ( VerifyXML(&inXMLData) )
{
if ( WriteXMLConfig(inXMLData) == eDSNoErr )
InitializeWithXML( inXMLData );
}
CFRelease( inXMLData );
}
return eDSNoErr;
}
SInt32 CLDAPv3Configs::AddToXMLConfig( CFDataRef inXMLData )
{
SInt32 siResult = eDSCorruptBuffer;
CFMutableDictionaryRef configDict = NULL;
CFMutableDictionaryRef xConfigDict = NULL;
if ( inXMLData != NULL )
{
configDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inXMLData,
kCFPropertyListMutableContainers,
NULL );
if ( configDict != NULL && CFDictionaryGetTypeID() == CFGetTypeID(configDict) )
{
CFDataRef ourXMLData = NULL;
if ( ReadXMLConfig(&ourXMLData) == eDSNoErr )
{
xConfigDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
ourXMLData,
kCFPropertyListMutableContainers,
NULL );
if ( xConfigDict != NULL && CFDictionaryGetTypeID() == CFGetTypeID(xConfigDict) )
{
CFMutableArrayRef cfMutableArrayRef;
cfMutableArrayRef = (CFMutableArrayRef) CFDictionaryGetValue( xConfigDict, CFSTR(kXMLConfigArrayKey) );
if ( cfMutableArrayRef != NULL )
{
CFArrayAppendValue( cfMutableArrayRef, configDict );
}
else {
cfMutableArrayRef = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue( cfMutableArrayRef, configDict);
CFDictionarySetValue( xConfigDict, CFSTR(kXMLConfigArrayKey), cfMutableArrayRef );
DSCFRelease( cfMutableArrayRef );
}
CFDataRef xmlBlob = CFPropertyListCreateXMLData( kCFAllocatorDefault, xConfigDict );
if ( xmlBlob != NULL )
{
NewXMLConfig( xmlBlob );
DSCFRelease( xmlBlob );
}
siResult = eDSNoErr;
}
DSCFRelease( xConfigDict );
}
}
DSCFRelease( configDict );
}
return siResult;
}
CFMutableDictionaryRef CLDAPv3Configs::FindMatchingUUIDAndName( CFDictionaryRef inConfig, const char *inNodeName, CFStringRef inUUID )
{
CFArrayRef cfConfigArray = (CFArrayRef) CFDictionaryGetValue( inConfig, CFSTR(kXMLConfigArrayKey) );
CFIndex iCount = (cfConfigArray != NULL ? CFArrayGetCount(cfConfigArray) : 0);
CFStringRef cfNodeName = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault, inNodeName, kCFStringEncodingUTF8,
kCFAllocatorNull );
CFMutableDictionaryRef nodeConfigDict = NULL;
for ( CFIndex ii = 0; ii < iCount; ii++ )
{
CFMutableDictionaryRef cfTempDict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( cfConfigArray, ii );
bool bNameMatch = false;
if ( cfTempDict == NULL )
continue;
CFStringRef cfUUID = (CFStringRef) CFDictionaryGetValue( cfTempDict, CFSTR(kXMLConfigurationUUID) );
if ( cfUUID != NULL && CFStringCompare(cfUUID, inUUID, 0) == kCFCompareEqualTo )
{
CFStringRef cfString = (CFStringRef) CFDictionaryGetValue( cfTempDict, CFSTR(kXMLNodeName) );
if ( cfString != NULL && CFStringCompare(cfString, cfNodeName, 0) == kCFCompareEqualTo )
{
bNameMatch = true;
}
else
{
cfString = (CFStringRef) CFDictionaryGetValue( cfTempDict, CFSTR(kXMLServerKey) );
if ( cfString != NULL && CFStringCompare(cfString, cfNodeName, 0) == kCFCompareEqualTo )
{
bNameMatch = true;
}
}
}
if ( bNameMatch == true )
{
nodeConfigDict = cfTempDict;
break;
}
}
DSCFRelease( cfNodeName );
return nodeConfigDict;
}
void CLDAPv3Configs::UpdateSecurityPolicyForUUID( const char *inNodeName, CFStringRef inUUID, CFDictionaryRef inConfiguredSecPolicy,
CFDictionaryRef inSupportedSecLevel )
{
CFMutableDictionaryRef configDict = NULL;
CFMutableDictionaryRef nodeConfigDict = NULL;
CFDataRef configXML = NULL;
if ( inNodeName == NULL || inUUID == NULL ) return;
fXMLConfigLock.WaitLock();
if ( ReadXMLConfig(&configXML) == eDSNoErr )
{
configDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
configXML,
kCFPropertyListMutableContainersAndLeaves,
NULL );
if ( configDict != NULL && CFGetTypeID(configDict) == CFDictionaryGetTypeID() )
{
nodeConfigDict = FindMatchingUUIDAndName( configDict, inNodeName, inUUID );
}
if ( nodeConfigDict != NULL )
{
bool bChangedConfig = false;
bool bChangedPolicy = false;
CFDictionaryRef cfSupported = (CFDictionaryRef) CFDictionaryGetValue( nodeConfigDict, CFSTR(kXMLSupportedSecurityKey) );
if ( inSupportedSecLevel != NULL )
{
if ( cfSupported == NULL || CFEqual(cfSupported, inSupportedSecLevel) == false )
{
CFDictionarySetValue( nodeConfigDict, CFSTR(kXMLSupportedSecurityKey), inSupportedSecLevel );
bChangedConfig = true;
}
}
else if ( cfSupported != NULL )
{
CFDictionaryRemoveValue( nodeConfigDict, CFSTR(kXMLSupportedSecurityKey) );
bChangedPolicy = true;
}
CFDictionaryRef cfConfigured = (CFDictionaryRef) CFDictionaryGetValue( nodeConfigDict, CFSTR(kXMLConfiguredSecurityKey) );
if ( inConfiguredSecPolicy != NULL )
{
if ( cfConfigured == NULL || CFEqual(cfConfigured, inConfiguredSecPolicy) == false )
{
CFDictionarySetValue( nodeConfigDict, CFSTR(kXMLConfiguredSecurityKey), inConfiguredSecPolicy );
bChangedConfig = true;
bChangedPolicy = true;
}
}
else if ( cfConfigured != NULL )
{
CFDictionaryRemoveValue( nodeConfigDict, CFSTR(kXMLConfiguredSecurityKey) );
bChangedConfig = true;
bChangedPolicy = true;
}
if ( bChangedConfig )
{
CFDataRef aXMLData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict );
if ( aXMLData != NULL )
{
WriteXMLConfig( aXMLData );
DSCFRelease( aXMLData );
}
}
if ( bChangedPolicy )
{
DbgLog( kLogPlugin, "CLDAPv3Configs::UpdateSecurityPolicyForUUID - [%s] Updated Security Policies from Directory.", inNodeName );
syslog( LOG_ALERT, "LDAPv3: [%s] Updated Security Policies from Directory.", inNodeName );
}
}
}
fXMLConfigLock.SignalLock();
DSCFRelease( configXML );
DSCFRelease( configDict );
}
void CLDAPv3Configs::UpdateReplicaListForUUID( const char *inNodeName, CFStringRef inUUID, CFArrayRef inReplicaHostnames,
CFArrayRef inWriteableHostnames )
{
CFMutableDictionaryRef configDict = NULL;
CFMutableDictionaryRef nodeConfigDict = NULL;
CFDataRef configXML = NULL;
if ( inNodeName == NULL || inUUID == NULL ) return;
fXMLConfigLock.WaitLock();
if ( ReadXMLConfig(&configXML) == eDSNoErr )
{
configDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
configXML,
kCFPropertyListMutableContainersAndLeaves,
NULL );
if ( configDict != NULL && CFGetTypeID(configDict) == CFDictionaryGetTypeID() )
{
nodeConfigDict = FindMatchingUUIDAndName( configDict, inNodeName, inUUID );
}
if ( nodeConfigDict != NULL )
{
CFArrayRef cfRepArrayRef = NULL;
bool bUpdated = false;
cfRepArrayRef = (CFArrayRef) CFDictionaryGetValue( nodeConfigDict, CFSTR(kXMLReplicaHostnameListArrayKey) );
if ( inReplicaHostnames != NULL )
{
if ( cfRepArrayRef == NULL || CFEqual(inReplicaHostnames, cfRepArrayRef) == false )
{
CFDictionarySetValue( nodeConfigDict, CFSTR(kXMLReplicaHostnameListArrayKey), inReplicaHostnames );
bUpdated = true;
}
}
else if ( cfRepArrayRef != NULL )
{
CFDictionaryRemoveValue( nodeConfigDict, CFSTR( kXMLReplicaHostnameListArrayKey ) );
bUpdated = true;
}
cfRepArrayRef = (CFArrayRef) CFDictionaryGetValue( nodeConfigDict, CFSTR(kXMLWriteableHostnameListArrayKey) );
if ( inWriteableHostnames != NULL )
{
if ( cfRepArrayRef == NULL || CFEqual(inWriteableHostnames, cfRepArrayRef) == false )
{
CFDictionarySetValue( nodeConfigDict, CFSTR(kXMLWriteableHostnameListArrayKey), inWriteableHostnames );
bUpdated = true;
}
}
else if ( cfRepArrayRef != NULL )
{
CFDictionaryRemoveValue( nodeConfigDict, CFSTR( kXMLWriteableHostnameListArrayKey ) );
bUpdated = true;
}
if ( bUpdated )
{
CFDataRef aXMLData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict );
if ( aXMLData != NULL )
{
WriteXMLConfig( aXMLData );
DSCFRelease( aXMLData );
}
DbgLog( kLogPlugin, "CLDAPv3Configs::UpdateReplicaListForUUID - [%s] Updated replica list from Directory.", inNodeName );
}
}
}
DSCFRelease( configDict );
DSCFRelease( configXML );
fXMLConfigLock.SignalLock();
}
void CLDAPv3Configs::UpdateServerMappingsForUUID( const char *inNodeName, CFStringRef inUUID, CFArrayRef inAttrTypeMapArray,
CFArrayRef inRecordTypeMapArray )
{
CFMutableDictionaryRef configDict = NULL;
CFMutableDictionaryRef nodeConfigDict = NULL;
CFDataRef configXML = NULL;
if ( inNodeName == NULL || inUUID == NULL ) return;
fXMLConfigLock.WaitLock();
if ( ReadXMLConfig(&configXML) == eDSNoErr )
{
configDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
configXML,
kCFPropertyListMutableContainersAndLeaves,
NULL );
if ( configDict != NULL && CFGetTypeID(configDict) == CFDictionaryGetTypeID() )
{
nodeConfigDict = FindMatchingUUIDAndName( configDict, inNodeName, inUUID );
}
if ( nodeConfigDict != NULL )
{
bool bUpdated = false;
if ( inAttrTypeMapArray != NULL )
{
CFDictionarySetValue( nodeConfigDict, CFSTR(kXMLAttrTypeMapArrayKey), inAttrTypeMapArray );
bUpdated = true;
}
else if ( CFDictionaryContainsKey(nodeConfigDict, CFSTR(kXMLAttrTypeMapArrayKey)) )
{
CFDictionaryRemoveValue( nodeConfigDict, CFSTR(kXMLAttrTypeMapArrayKey) );
bUpdated = true;
}
if ( inRecordTypeMapArray != NULL )
{
CFDictionarySetValue( nodeConfigDict, CFSTR(kXMLRecordTypeMapArrayKey), inRecordTypeMapArray );
bUpdated = true;
}
else if ( CFDictionaryContainsKey(nodeConfigDict, CFSTR(kXMLRecordTypeMapArrayKey)) )
{
CFDictionaryRemoveValue( nodeConfigDict, CFSTR(kXMLRecordTypeMapArrayKey) );
bUpdated = true;
}
if ( bUpdated )
{
CFDataRef aXMLData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict );
if ( aXMLData != NULL )
{
WriteXMLConfig( aXMLData );
DSCFRelease( aXMLData );
}
DbgLog( kLogPlugin, "CLDAPv3Configs::UpdateServerMappingsForUUID - [%s] Updated server mappings from Directory.", inNodeName );
}
}
}
DSCFRelease( configDict );
DSCFRelease( configXML );
fXMLConfigLock.SignalLock();
}
#pragma mark -
#pragma mark Get Connection for a node name
bool CLDAPv3Configs::LocalServerIsReplica( void )
{
bool bResult = false;
char *fileContents = NULL;
try
{
CFile slapdConf("/etc/openldap/slapd.conf");
if ( !slapdConf.is_open() )
throw(-1);
CFile slapdMacOSXConf;
fileContents = (char*)calloc( 1, slapdConf.FileSize() + 1 );
if ( fileContents != NULL )
{
slapdConf.Read( fileContents, slapdConf.FileSize() );
if ((strncmp( fileContents, "updateref", sizeof("updateref") - 1 ) == 0)
|| (strstr( fileContents, "\nupdateref" ) != NULL))
{
bResult = true;
}
free( fileContents );
fileContents = NULL;
}
if ( !bResult )
{
slapdMacOSXConf.open("/etc/openldap/slapd_macosxserver.conf");
fileContents = (char*)calloc( 1, slapdMacOSXConf.FileSize() + 1 );
}
if (fileContents != NULL)
{
slapdMacOSXConf.Read( fileContents, slapdMacOSXConf.FileSize() );
if ((strncmp( fileContents, "updateref", sizeof("updateref") - 1 ) == 0)
|| (strstr( fileContents, "\nupdateref" ) != NULL))
{
bResult = true;
}
free( fileContents );
fileContents = NULL;
}
}
catch ( ... )
{
}
DSFree( fileContents );
return bResult;
}
CLDAPConnection *CLDAPv3Configs::CreateConnectionForNode( const char *inNodeName )
{
CLDAPConnection *pConnection = NULL;
fNodeConfigMapMutex.WaitLock();
LDAPNodeConfigMapI iter = fNodeConfigMap.find( inNodeName );
if ( iter != fNodeConfigMap.end() )
pConnection = new CLDAPConnection( iter->second );
if ( pConnection == NULL )
{
iter = fDynamicNodeConfigMap.find( inNodeName );
if ( iter != fDynamicNodeConfigMap.end() )
pConnection = new CLDAPConnection( iter->second );
}
if ( pConnection == NULL )
{
if ( ldap_is_ldapi_url(inNodeName) )
{
if ( gServerOS == true && LocalServerIsReplica() == false )
{
CLDAPNodeConfig *newConfig = new CLDAPNodeConfig( NULL, inNodeName, false );
if ( newConfig != NULL )
{
pConnection = new CLDAPConnection( newConfig );
fDynamicNodeConfigMap[inNodeName] = newConfig->Retain();
DSRelease( newConfig );
}
}
}
else if ( ldap_is_ldap_url(inNodeName) )
{
CLDAPNodeConfig *newConfig = new CLDAPNodeConfig( NULL, inNodeName, false );
if ( newConfig != NULL )
{
pConnection = new CLDAPConnection( newConfig );
fDynamicNodeConfigMap[inNodeName] = newConfig->Retain();
DSRelease( newConfig );
}
}
}
fNodeConfigMapMutex.SignalLock();
return pConnection;
}
#pragma mark -
#pragma mark Writing Server mappings to a server
SInt32 CLDAPv3Configs::WriteServerMappings( char *userName, char *password, CFDataRef inMappings )
{
SInt32 siResult = eDSNoErr;
LDAP *serverHost = NULL;
CFPropertyListRef configPropertyList = NULL;
CFDictionaryRef serverConfigDict = NULL;
char *server = NULL;
int portNumber = 389;
int openCloseTO = kLDAPDefaultOpenCloseTimeoutInSeconds;
CFStringRef cfStringRef = NULL;
CFBooleanRef cfBool = NULL;
CFNumberRef cfNumber = NULL;
char *mapSearchBase = NULL;
bool bIsSSL = false;
int ldapReturnCode = 0;
int version = -1;
int bindMsgId = 0;
LDAPMessage *result = NULL;
char *ldapDNString = NULL;
UInt32 ldapDNLength = 0;
char *ourXMLBlob = NULL;
char *ouvals[2];
char *mapvals[2];
char *ocvals[3];
LDAPMod oumod;
LDAPMod mapmod;
LDAPMod ocmod;
LDAPMod *mods[4];
try
{
if (inMappings != NULL)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inMappings,
kCFPropertyListImmutable,
NULL);
if (configPropertyList != NULL )
{
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
serverConfigDict = (CFDictionaryRef) configPropertyList;
}
if (serverConfigDict != NULL)
{
cfStringRef = (CFStringRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLServerKey ) );
if ( cfStringRef != NULL && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
UInt32 uiLength = (UInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
server = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, server, uiLength, kCFStringEncodingUTF8 );
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLOpenCloseTimeoutSecsKey ) );
if ( cfNumber != NULL )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &openCloseTO);
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLIsSSLFlagKey ) );
if (cfBool != NULL)
{
bIsSSL = CFBooleanGetValue( cfBool );
if (bIsSSL)
{
portNumber = LDAPS_PORT;
}
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLPortNumberKey ) );
if ( cfNumber != NULL )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &portNumber);
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLMapSearchBase ) );
if ( cfStringRef != NULL && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
UInt32 uiLength = (UInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
mapSearchBase = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, mapSearchBase, uiLength, kCFStringEncodingUTF8 );
}
}
CFRelease(configPropertyList); configPropertyList = NULL;
}
serverHost = ldap_init( server, portNumber );
if ( serverHost == NULL ) throw( (SInt32)eDSCannotAccessSession );
if ( bIsSSL )
{
int ldapOptVal = LDAP_OPT_X_TLS_HARD;
ldap_set_option(serverHost, LDAP_OPT_X_TLS, &ldapOptVal);
}
version = LDAP_VERSION3;
ldap_set_option( serverHost, LDAP_OPT_PROTOCOL_VERSION, &version );
bindMsgId = ldap_bind( serverHost, userName, password, LDAP_AUTH_SIMPLE );
if (openCloseTO == 0)
{
ldapReturnCode = ldap_result(serverHost, bindMsgId, 0, NULL, &result);
}
else
{
struct timeval tv;
tv.tv_sec = openCloseTO;
tv.tv_usec = 0;
ldapReturnCode = ldap_result(serverHost, bindMsgId, 0, &tv, &result);
}
if ( ldapReturnCode == -1 )
{
throw( (SInt32)eDSCannotAccessSession );
}
else if ( ldapReturnCode == 0 )
{
ldap_unbind_ext( serverHost, NULL, NULL );
serverHost = NULL;
throw( (SInt32)eDSCannotAccessSession );
}
else if ( ldap_result2error(serverHost, result, 1) != LDAP_SUCCESS )
{
throw( (SInt32)eDSCannotAccessSession );
}
if ( (serverHost != NULL) && (mapSearchBase != NULL) )
{
ldapDNLength = 21 + strlen(mapSearchBase);
ldapDNString = (char *)calloc(1, ldapDNLength + 1);
strcpy(ldapDNString,"ou = macosxodconfig, ");
strcat(ldapDNString,mapSearchBase);
ldapReturnCode = ldap_delete_s( serverHost, ldapDNString);
if ( ( ldapReturnCode == LDAP_INSUFFICIENT_ACCESS ) || ( ldapReturnCode == LDAP_INVALID_CREDENTIALS ) )
{
siResult = eDSPermissionError;
}
else if ( ldapReturnCode == LDAP_NO_SUCH_OBJECT )
{
siResult = eDSRecordNotFound;
}
else if ( ldapReturnCode != LDAP_SUCCESS )
{
siResult = eDSBogusServer;
}
if ( (siResult == eDSRecordNotFound) || (siResult == eDSNoErr) )
{
CFRange aRange;
aRange.location = 0;
aRange.length = CFDataGetLength(inMappings);
ourXMLBlob = (char *) calloc(1, aRange.length + 1);
CFDataGetBytes( inMappings, aRange, (UInt8*)ourXMLBlob );
ouvals[0] = (char *)"macosxodconfig";
ouvals[1] = NULL;
oumod.mod_op = 0;
oumod.mod_type = (char *)"ou";
oumod.mod_values = ouvals;
mapvals[0] = ourXMLBlob;
mapvals[1] = NULL;
mapmod.mod_op = 0;
mapmod.mod_type = (char *)"description";
mapmod.mod_values = mapvals;
ocvals[0] = (char *)"top";
ocvals[1] = (char *)"organizationalUnit";
ocvals[2] = NULL;
ocmod.mod_op = 0;
ocmod.mod_type = (char *)"objectclass";
ocmod.mod_values = ocvals;
mods[0] = &oumod;
mods[1] = &mapmod;
mods[2] = &ocmod;
mods[3] = NULL;
ldapReturnCode = 0;
siResult = eDSNoErr;
ldapReturnCode = ldap_add_s( serverHost, ldapDNString, mods);
if ( ( ldapReturnCode == LDAP_INSUFFICIENT_ACCESS ) || ( ldapReturnCode == LDAP_INVALID_CREDENTIALS ) )
{
siResult = eDSPermissionError;
}
else if ( ldapReturnCode == LDAP_ALREADY_EXISTS )
{
siResult = eDSRecordAlreadyExists;
}
else if ( ldapReturnCode == LDAP_NO_SUCH_OBJECT )
{
siResult = eDSRecordNotFound;
}
else if ( ldapReturnCode != LDAP_SUCCESS )
{
siResult = eDSBogusServer;
}
DSFree( ourXMLBlob );
} } }
} catch ( SInt32 err )
{
siResult = err;
if (configPropertyList != NULL)
{
CFRelease(configPropertyList); configPropertyList = NULL;
}
}
if ( serverHost != NULL )
{
ldap_unbind_ext( serverHost, NULL, NULL );
serverHost = NULL;
}
if ( mapSearchBase != NULL )
{
free( mapSearchBase );
mapSearchBase = NULL;
}
if ( ourXMLBlob != NULL )
{
free( ourXMLBlob );
ourXMLBlob = NULL;
}
if ( ldapDNString != NULL )
{
free( ldapDNString );
ldapDNString = NULL;
}
return( siResult );
}
#pragma mark -
#pragma mark Initialize with new XML data
SInt32 CLDAPv3Configs::InitializeWithXML( CFDataRef inXMLData )
{
SInt32 siResult = eDSNoErr;
CFMutableDictionaryRef configDict = NULL;
bool bConfigUpdated = false;
const char *nodeName = NULL;
if ( inXMLData == NULL ) return eDSNullParameter;
fNodeConfigMapMutex.WaitLock();
configDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inXMLData,
kCFPropertyListImmutable,
NULL );
if ( configDict != NULL && CFDictionaryGetTypeID() == CFGetTypeID(configDict) )
{
CFStringRef cfVersion = (CFStringRef) CFDictionaryGetValue( configDict, CFSTR(kXMLLDAPVersionKey) );
if ( cfVersion != NULL )
{
if ( CFStringCompare(cfVersion, CFSTR(kDSLDAPPrefs_CurrentVersion), 0) != kCFCompareEqualTo )
{
CFDictionarySetValue( configDict, CFSTR(kXMLLDAPVersionKey), CFSTR(kDSLDAPPrefs_CurrentVersion) );
bConfigUpdated = true;
}
CFArrayRef cfArrayRef = (CFArrayRef) CFDictionaryGetValue( configDict, CFSTR(kXMLConfigArrayKey) );
if ( cfArrayRef != NULL )
{
CFIndex cfConfigCount = CFArrayGetCount( cfArrayRef );
LDAPNodeConfigMap newConfigMap;
for ( CFIndex iConfigIndex = 0; iConfigIndex < cfConfigCount; iConfigIndex++ )
{
CFMutableDictionaryRef serverConfigDict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( cfArrayRef, iConfigIndex );
if ( serverConfigDict != NULL )
{
CFStringRef cfUUID = (CFStringRef) CFDictionaryGetValue( serverConfigDict, CFSTR(kXMLConfigurationUUID) );
if ( cfUUID != NULL )
{
char *cStr = NULL;
CFStringRef cfNodeName = (CFStringRef) CFDictionaryGetValue( serverConfigDict, CFSTR(kXMLNodeName) );
if ( cfNodeName == NULL )
cfNodeName = (CFStringRef) CFDictionaryGetValue( serverConfigDict, CFSTR(kXMLServerKey) );
if ( cfNodeName != NULL )
nodeName = BaseDirectoryPlugin::GetCStringFromCFString( cfNodeName, &cStr );
if ( nodeName != NULL )
{
CLDAPNodeConfig *pConfig = NULL;
CFBooleanRef cfBool = (CFBooleanRef) CFDictionaryGetValue(serverConfigDict, CFSTR("LDAPv2 Read Only") );
if ( cfBool != NULL && CFBooleanGetValue(cfBool) == TRUE ) {
syslog( LOG_NOTICE, "LDAPv2 is no longer supported for '%s', will use LDAPv3", nodeName );
DbgLog( kLogNotice, "CLDAPv3Configs::InitializeWithXML - LDAPv2 is no longer supported for '%s', will use LDAPv3", nodeName );
CFDictionaryRemoveValue( serverConfigDict, CFSTR("LDAPv2 Read Only") );
}
LDAPNodeConfigMapI iter = fNodeConfigMap.find( nodeName );
if ( iter != fNodeConfigMap.end() )
{
pConfig = iter->second;
if ( pConfig->fDHCPLDAPServer == true || CFStringCompare(pConfig->fConfigUUID, cfUUID, 0) != kCFCompareEqualTo )
pConfig = NULL;
else
pConfig->Retain(); }
if ( pConfig == NULL )
{
pConfig = new CLDAPNodeConfig( this, nodeName, cfUUID );
tDataListPtr pldapName = dsBuildListFromStringsPriv( "LDAPv3", nodeName, NULL );
if ( pldapName != NULL )
{
CServerPlugin::_RegisterNode( fPlugInSignature, pldapName, kDirNodeType );
dsDataListDeallocatePriv( pldapName );
DSFree( pldapName );
}
}
if ( pConfig != NULL )
{
pConfig->UpdateConfiguraton( serverConfigDict, false );
newConfigMap[nodeName] = pConfig;
}
}
DSFree( cStr );
}
}
}
if ( fDHCPLDAPServers != NULL )
{
bool bNodesAdded = false;
CFIndex iCount = CFArrayGetCount( fDHCPLDAPServers );
for ( CFIndex ii = 0; ii < iCount; ii++ )
{
char *cStr = NULL;
CFStringRef cfServer = (CFStringRef) CFArrayGetValueAtIndex( fDHCPLDAPServers, ii );
const char *pServer = BaseDirectoryPlugin::GetCStringFromCFString( cfServer, &cStr );
if ( pServer == NULL )
continue;
CLDAPNodeConfig *pNewConfig = new CLDAPNodeConfig( this, pServer, true );
if ( pNewConfig != NULL && pNewConfig->fNodeName )
{
if ( newConfigMap.find(pNewConfig->fNodeName) == newConfigMap.end() )
{
newConfigMap[pNewConfig->fNodeName] = pNewConfig->Retain();
tDataListPtr pldapName = dsBuildListFromStringsPriv( "LDAPv3", pNewConfig->fNodeName, NULL );
if ( pldapName != NULL )
{
bNodesAdded = true;
CServerPlugin::_RegisterNode( fPlugInSignature, pldapName, kDirNodeType );
dsDataListDeallocatePriv( pldapName );
DSFree( pldapName );
}
}
else
{
DbgLog( kLogPlugin, "CLDAPv3Configs::InitializeWithXML - DHCP Option 95 node %s will be deleted - have static node",
pNewConfig->fNodeName );
}
DSRelease( pNewConfig );
}
DSFree( cStr );
}
if ( bNodesAdded && gCacheNode != NULL )
gCacheNode->EmptyCacheEntryType( CACHE_ENTRY_TYPE_NEGATIVE );
}
for ( LDAPNodeConfigMapI iter = fNodeConfigMap.begin(); iter != fNodeConfigMap.end(); iter++ )
{
if ( newConfigMap.find(iter->first) == newConfigMap.end() )
{
tDataListPtr ldapName = dsBuildListFromStringsPriv( "LDAPv3", iter->first.c_str(), NULL );
if ( ldapName != NULL )
{
if ( gCacheNode != NULL )
gCacheNode->EmptyCacheEntryType( CACHE_ENTRY_TYPE_ALL );
CServerPlugin::_UnregisterNode( fPlugInSignature, ldapName );
dsDataListDeallocatePriv( ldapName );
DSFree( ldapName );
}
char *cStr = NULL;
const char *uuidStr = BaseDirectoryPlugin::GetCStringFromCFString( iter->second->fConfigUUID, &cStr );
DbgLog( kLogPlugin, "CLDAPv3Configs::InitializeWithXML - Removing config for node %s - %s", iter->first.c_str(), uuidStr );
DSFree( cStr );
iter->second->DeleteConfiguration();
}
iter->second->Release();
}
fNodeConfigMap = newConfigMap;
SCDynamicStoreRef store = SCDynamicStoreCreate( NULL, CFSTR("DirectoryService"), NULL, NULL );
if ( store != NULL )
{
SCDynamicStoreNotifyValue( store, CFSTR(kDSStdNotifyDHCPOptionsAvailable) );
DSCFRelease( store );
}
DbgLog( kLogPlugin, "CLDAPv3Configs::InitializeWithXML - Have successfully added or updated Node configurations" );
}
siResult = eDSNoErr;
}
else
{
siResult = eDSVersionMismatch;
}
}
DSCFRelease( configDict );
fNodeConfigMapMutex.SignalLock();
return siResult;
}
#pragma mark -
#pragma mark Other support functions
void CLDAPv3Configs::NetworkTransition( void )
{
fNodeConfigMapMutex.WaitLock();
for ( LDAPNodeConfigMapI iter = fNodeConfigMap.begin(); iter != fNodeConfigMap.end(); iter++ )
iter->second->NetworkTransition();
fNodeConfigMapMutex.SignalLock();
}
void CLDAPv3Configs::PeriodicTask( void )
{
fNodeConfigMapMutex.WaitLock();
for ( LDAPNodeConfigMapI iter = fDynamicNodeConfigMap.begin(); iter != fDynamicNodeConfigMap.end(); )
{
if ( iter->second->RetainCount() == 1 )
{
DbgLog( kLogPlugin, "CLDAPv3Configs::PeriodicTask - removing dynamic node %s from table - References: 0", iter->first.c_str() );
iter->second->Release();
fDynamicNodeConfigMap.erase( iter++ );
continue;
}
iter++;
}
fNodeConfigMapMutex.SignalLock();
}
#pragma mark -
#pragma mark DHCP Option 95 stuff
void CLDAPv3Configs::DHCPLDAPConfigNotification( SCDynamicStoreRef cfStore, CFArrayRef changedKeys, void *inInfo )
{
CLDAPv3Configs *pConfig = (CLDAPv3Configs *) inInfo;
DbgLog( kLogApplication, "CLDAPv3Configs::DHCPLDAPConfigNotification - Option 95 support changed to <%s> from Search Node",
(gDHCPLDAPEnabled ? "on" : "off") );
pConfig->WatchForDHCPPacket();
if ( pConfig->CheckForDHCPPacket() )
pConfig->RegisterAllNodes();
}
void CLDAPv3Configs::DHCPPacketStateNotification( SCDynamicStoreRef cfStore, CFArrayRef changedKeys, void *inInfo )
{
CLDAPv3Configs *pConfig = (CLDAPv3Configs *) inInfo;
DbgLog( kLogApplication, "CLDAPv3Configs::DHCPPacketStateNotification - Looking for Option 95 in DHCP info" );
if ( pConfig->CheckForDHCPPacket() )
pConfig->RegisterAllNodes();
}
bool CLDAPv3Configs::CheckForDHCPPacket( void )
{
bool bNewDHCPConfig = false;
CFMutableArrayRef cfNewServers = NULL;
fNodeConfigMapMutex.WaitLock();
if ( gDHCPLDAPEnabled )
{
CFDictionaryRef ourDHCPInfo = SCDynamicStoreCopyDHCPInfo( NULL, NULL );
if ( ourDHCPInfo != NULL )
{
CFDataRef ourDHCPServersData = DHCPInfoGetOptionData( ourDHCPInfo, 95 );
if ( ourDHCPServersData != NULL )
{
CFStringRef ourDHCPString = CFStringCreateWithBytes( kCFAllocatorDefault,
CFDataGetBytePtr(ourDHCPServersData),
CFDataGetLength(ourDHCPServersData),
kCFStringEncodingUTF8,
false );
if ( ourDHCPString != NULL )
{
cfNewServers = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
CFArrayRef tempServers = CFStringCreateArrayBySeparatingStrings( kCFAllocatorDefault, ourDHCPString, CFSTR(" ") );
if ( tempServers != NULL )
{
CFIndex total = CFArrayGetCount( tempServers );
for ( CFIndex ii = 0; ii < total; ii++ )
{
CFStringRef value = (CFStringRef) CFArrayGetValueAtIndex( tempServers, ii );
LDAPURLDesc *ludpp = NULL;
char *tmpStr = NULL;
const char *url = BaseDirectoryPlugin::GetCStringFromCFString( value, &tmpStr );
if ( url != NULL && url[0] != '\0' && ldap_url_parse(url, &ludpp) == LDAP_SUCCESS ) {
if ( ludpp->lud_host != NULL ) {
CFArrayAppendValue( cfNewServers, value );
}
else {
DbgLog( kLogError, "CLDAPv3Configs::CheckForDHCPPacket - No LDAP host in the Option 95 packet '%s'", url );
}
ldap_free_urldesc( ludpp );
ludpp = NULL;
} else if ( url != NULL ) {
DbgLog( kLogError, "CLDAPv3Configs::CheckForDHCPPacket - Invalid Option 95 server '%s'", url );
}
DSFree( tmpStr );
}
DSCFRelease( tempServers );
}
if ( fDHCPLDAPServers == NULL || CFEqual(cfNewServers, fDHCPLDAPServers) == false )
{
bNewDHCPConfig = true;
DbgLog( kLogPlugin, "CLDAPv3Configs::CheckForDHCPPacket - New Option 95 DHCP information available" );
}
DSCFRelease( ourDHCPString );
}
}
DSCFRelease( ourDHCPInfo );
}
}
if ( cfNewServers != NULL )
{
DSCFRelease( fDHCPLDAPServers );
fDHCPLDAPServers = cfNewServers;
}
else if ( fDHCPLDAPServers != NULL )
{
DSCFRelease( fDHCPLDAPServers );
DbgLog( kLogPlugin, "CLDAPv3Configs::CheckForDHCPPacket - clearing previous server list no longer available" );
bNewDHCPConfig = true;
}
fNodeConfigMapMutex.SignalLock();
return bNewDHCPConfig;
}
void CLDAPv3Configs::WatchForDHCPPacket( void )
{
static CFRunLoopSourceRef cfNotifyRLS = NULL;
static pthread_mutex_t localMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock( &localMutex );
if (gDHCPLDAPEnabled && cfNotifyRLS == NULL)
{
SCDynamicStoreContext context = { 0, this, NULL, NULL, NULL };
CFStringRef dhcpKey = SCDynamicStoreKeyCreateNetworkServiceEntity( kCFAllocatorDefault, kSCDynamicStoreDomainState,
kSCCompAnyRegex, kSCEntNetDHCP );
CFStringRef ipv4Key = SCDynamicStoreKeyCreateNetworkGlobalEntity( kCFAllocatorDefault, kSCDynamicStoreDomainState,
kSCEntNetIPv4 );
CFArrayRef patterns = CFArrayCreate( kCFAllocatorDefault, (CFTypeRef *)&dhcpKey, 1, &kCFTypeArrayCallBacks );
CFArrayRef keys = CFArrayCreate( kCFAllocatorDefault, (CFTypeRef *)&ipv4Key, 1, &kCFTypeArrayCallBacks );
SCDynamicStoreRef store = SCDynamicStoreCreate( kCFAllocatorDefault, CFSTR("CLDAPv3Configs::WatchForDHCPPacket"),
DHCPPacketStateNotification, &context );
if ( store != NULL )
{
SCDynamicStoreSetNotificationKeys( store, keys, patterns );
cfNotifyRLS = SCDynamicStoreCreateRunLoopSource( NULL, store, 0 );
if (cfNotifyRLS != NULL)
{
CFRunLoopAddSource( gPluginRunLoop, cfNotifyRLS, kCFRunLoopDefaultMode );
DbgLog( kLogPlugin, "CLDAPv3Configs::WatchForDHCPPacket - watching for LDAP options in DHCP packets" );
}
else
{
syslog(LOG_ALERT, "CLDAPv3Configs::WatchForDHCPPacket - failed to create runloop source for DHCP Network Notifications");
}
}
else
{
syslog(LOG_ALERT, "CLDAPv3Configs::WatchForDHCPPacket - failed to register for DHCP Network Notifications");
}
DSCFRelease( dhcpKey );
DSCFRelease( ipv4Key );
DSCFRelease( keys );
DSCFRelease( patterns );
DSCFRelease( store );
}
else if ( gDHCPLDAPEnabled == false && cfNotifyRLS != NULL )
{
CFRunLoopRemoveSource( gPluginRunLoop, cfNotifyRLS, kCFRunLoopDefaultMode );
DSCFRelease( cfNotifyRLS );
DbgLog( kLogPlugin, "CLDAPv3Configs::WatchForDHCPPacket - no longer watching for LDAP options in DHCP packets" );
}
pthread_mutex_unlock( &localMutex );
}
#pragma mark -
#pragma mark File Operations
SInt32 CLDAPv3Configs::ReadXMLConfig( CFDataRef *outXMLData )
{
CFDataRef xmlData = NULL;
SInt32 siResult = eDSNoErr;
bool bCorruptedFile = false;
CLDAPPlugInPrefs *prefsFile = NULL;
fXMLConfigLock.WaitLock();
prefsFile = new CLDAPPlugInPrefs();
if ( prefsFile != NULL )
{
xmlData = prefsFile->GetPrefsXML();
if ( xmlData )
{
if ( VerifyXML(&xmlData) == false )
{
const char *corruptPath = "/Library/Preferences/DirectoryService/DSLDAPv3PlugInConfigCorrupted.plist";
DbgLog( kLogPlugin, "CLDAPv3Configs::ReadXMLConfig - LDAP XML config file is corrupted" );
bCorruptedFile = true;
DSPrefs prefs = {0};
prefsFile->GetPrefs( &prefs );
rename( prefs.path, corruptPath );
}
}
else {
DbgLog( kLogPlugin, "CLDAPv3Configs::ReadXMLConfig - LDAP XML config file is unreadable" );
bCorruptedFile = true;
}
if ( bCorruptedFile )
{
if ( prefsFile != NULL )
delete prefsFile;
prefsFile = new CLDAPPlugInPrefs();
DbgLog( kLogPlugin, "CLDAPv3Configs::ReadXMLConfig - Writing a new LDAP XML config file" );
prefsFile->Save();
}
delete prefsFile;
}
if ( xmlData != NULL )
{
(*outXMLData) = xmlData;
siResult = eDSNoErr;
}
fXMLConfigLock.SignalLock();
return siResult;
}
SInt32 CLDAPv3Configs::WriteXMLConfig( CFDataRef inXMLData )
{
SInt32 siResult = eDSNoErr;
bool bWroteFile = false;
fXMLConfigLock.WaitLock();
CFMutableDictionaryRef configPropertyList =
(CFMutableDictionaryRef) CFPropertyListCreateFromXMLData(
kCFAllocatorDefault,
inXMLData,
kCFPropertyListMutableContainersAndLeaves,
NULL);
if ( configPropertyList != NULL )
{
CLDAPPlugInPrefs prefsFile;
DSPrefs prefs = {0};
prefsFile.GetPrefs( &prefs );
prefs.configs = (CFArrayRef) CFDictionaryGetValue( configPropertyList, CFSTR(kDSLDAPPrefs_LDAPServerConfigs) );
if ( prefs.configs != NULL ) {
prefsFile.SetPrefs( &prefs );
bWroteFile = (prefsFile.Save() == 0);
}
CFRelease( configPropertyList );
}
fXMLConfigLock.SignalLock();
if (bWroteFile)
{
DbgLog( kLogPlugin, "CLDAPv3Configs::WriteXMLConfig - Have written the LDAP XML config file" );
siResult = eDSNoErr;
}
else
{
DbgLog( kLogPlugin, "CLDAPv3Configs::WriteXMLConfig - LDAP XML config file has FAILED to been written" );
siResult = eDSPlugInConfigFileError;
}
return siResult;
}
bool CLDAPv3Configs::VerifyXML( CFDataRef *inOutXMLData )
{
bool verified = false;
CFMutableDictionaryRef configPropertyList = NULL;
if ( (*inOutXMLData) != NULL )
{
configPropertyList = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
(*inOutXMLData),
kCFPropertyListMutableContainersAndLeaves,
NULL );
if ( configPropertyList != NULL )
{
bool bUpdated = false;
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
verified = true;
CFArrayRef cfServerList = (CFArrayRef) CFDictionaryGetValue( configPropertyList, CFSTR(kXMLConfigArrayKey) );
if( cfServerList != NULL && CFGetTypeID(cfServerList) == CFArrayGetTypeID() )
{
CFIndex iCount = CFArrayGetCount( cfServerList );
for( CFIndex ii = 0; ii < iCount; ii++ )
{
CFMutableDictionaryRef cfConfig = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( cfServerList, ii );
if( CFGetTypeID(cfConfig) == CFDictionaryGetTypeID() )
{
if( CFDictionaryContainsKey( cfConfig, CFSTR(kXMLUseDNSReplicasFlagKey) ) == false )
{
CFDictionarySetValue( cfConfig, CFSTR(kXMLUseDNSReplicasFlagKey), kCFBooleanFalse );
bUpdated = true;
}
if ( CFDictionaryContainsKey(cfConfig, CFSTR(kXMLDeniedSASLMethods)) == false )
{
CFMutableArrayRef cfArray = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks );
CFArrayAppendValue( cfArray, CFSTR("DIGEST-MD5") );
CFDictionarySetValue( cfConfig, CFSTR(kXMLDeniedSASLMethods), cfArray );
DSCFRelease( cfArray );
bUpdated = true;
}
if ( CFDictionaryContainsKey( cfConfig, CFSTR(kXMLConfigurationUUID) ) == false )
{
CFUUIDRef cfUUID = CFUUIDCreate( kCFAllocatorDefault );
CFStringRef cfString = CFUUIDCreateString( kCFAllocatorDefault, cfUUID );
CFDictionarySetValue( cfConfig, CFSTR(kXMLConfigurationUUID), cfString );
DSCFRelease( cfUUID );
DSCFRelease( cfString );
bUpdated = true;
}
}
else
{
verified = false;
}
}
}
}
if( bUpdated && verified )
{
CFDataRef xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configPropertyList );
if ( xmlData != NULL )
{
CFRelease( *inOutXMLData );
(*inOutXMLData) = xmlData;
}
if ( bUpdated )
{
DbgLog( kLogPlugin, "CLDAPv3Configs::VerifyXML - Configuration updated saving the file" );
WriteXMLConfig( xmlData );
}
}
DSCFRelease( configPropertyList );
}
}
return verified;
}