CLDAPv3Configs.cpp [plain text]
#pragma mark Includes
#include <string.h> //used for strcpy, etc.
#include <stdlib.h> //used for malloc
#include <sys/types.h>
#include <sys/stat.h> //used for mkdir and stat
#include <syslog.h> //error logging
#include "GetMACAddress.h"
#include "CLDAPv3Configs.h"
#include "CLog.h"
#include "DSLDAPUtils.h"
#include "DirServices.h"
#include "DirServicesUtils.h"
#include "DirServicesConst.h"
#include <unistd.h>
#pragma mark -
#pragma mark Statics
LDAPConfigDataMap CLDAPv3Configs::fConfigMap;
DSMutexSemaphore CLDAPv3Configs::fConfigMapMutex;
#pragma mark -
#pragma mark sLDAPConfigData Struct Members
sLDAPConfigData::sLDAPConfigData( char *inUIname, char *inNodeName,
char *inServerName, int inOpenCloseTO,
int inIdleTO, int inDelayRebindTry,
int inSearchTO, int inPortNum,
bool inUseSecure, char *inAccount,
char *inPassword, char *inKerberosId,
bool inMakeDefLDAP, bool inServerMappings,
bool inIsSSL, char *inMapSearchBase,
int inSecurityLevel, int inSecurityLevelLoc, bool inReferrals,
bool inLDAPv2ReadOnly, bool inDNSReplicas )
{
fUIName = (inUIname ? strdup(inUIname) : NULL );
fNodeName = (inNodeName ? strdup(inNodeName) : NULL);
fServerName = (inServerName ? strdup(inServerName) : NULL);
fOpenCloseTimeout = inOpenCloseTO;
fIdleTimeout = inIdleTO;
fDelayRebindTry = inDelayRebindTry;
fServerPassword = (inPassword ? strdup(inPassword) : NULL );
fSearchTimeout = inSearchTO;
fServerAccount = (inAccount ? strdup(inAccount) : NULL );
fServerPort = inPortNum;
bSecureUse = inUseSecure;
bUseAsDefaultLDAP = inMakeDefLDAP;
bGetServerMappings = bServerMappings = inServerMappings;
bIsSSL = inIsSSL;
bLDAPv2ReadOnly = inLDAPv2ReadOnly;
bReferrals = inReferrals;
fMapSearchBase = (inMapSearchBase ? strdup(inMapSearchBase) : NULL );
fSecurityLevel = inSecurityLevel;
fSecurityLevelLoc = inSecurityLevelLoc;
fKerberosId = (inKerberosId ? strdup(inKerberosId) : NULL );
bUpdated = true;
fReplicaHosts = nil;
fObjectClassSchema = nil;
bBuildReplicaList = bGetSecuritySettings = true;
bOCBuilt = bAvail = false;
fReplicaHostnames = fWriteableHostnames = nil;
fRecordAttrMapDict = NULL;
fRecordTypeMapCFArray = nil;
fAttrTypeMapCFArray = nil;
fSASLmethods = nil;
fConfigLock = new DSMutexSemaphore();
fRefCount = 0;
bMarkToDelete = false;
bDNSReplicas = inDNSReplicas;
}
sLDAPConfigData::sLDAPConfigData( void )
{
fNodeName = fUIName = fServerName = NULL;
fOpenCloseTimeout = kLDAPDefaultOpenCloseTimeoutInSeconds;
fIdleTimeout = 2;
fDelayRebindTry = kLDAPDefaultRebindTryTimeoutInSeconds;
fSearchTimeout = kLDAPDefaultSearchTimeoutInSeconds;
fKerberosId = fServerPassword = fServerAccount = NULL;
fServerPort = LDAP_PORT;
bSecureUse = bUseAsDefaultLDAP = bServerMappings = bIsSSL = bLDAPv2ReadOnly = false;
fSecurityLevel = fSecurityLevelLoc = kSecNoSecurity;
bUpdated = true;
fMapSearchBase = NULL;
fReplicaHosts = nil;
fObjectClassSchema = nil;
bReferrals = bBuildReplicaList = bGetSecuritySettings = true;
bGetServerMappings = bOCBuilt = bAvail = false;
fReplicaHostnames = fWriteableHostnames = nil;
fRecordAttrMapDict = NULL;
fRecordTypeMapCFArray = nil;
fAttrTypeMapCFArray = nil;
fSASLmethods = nil;
fConfigLock = new DSMutexSemaphore();
fRefCount = 0;
bMarkToDelete = false;
bDNSReplicas = false;
}
sLDAPConfigData::~sLDAPConfigData(void)
{
fConfigLock->Wait();
DSDelete( fUIName );
DSDelete( fNodeName );
DSDelete( fServerName );
DSDelete( fReplicaHosts );
DSCFRelease( fReplicaHostnames );
DSCFRelease( fWriteableHostnames );
DSDelete( fServerPassword );
DSDelete( fServerAccount );
if (fObjectClassSchema != nil)
{
ObjectClassMapCI iter = fObjectClassSchema->begin();
while( iter != fObjectClassSchema->end() )
{
iter->second->fParentOCs.clear();
iter->second->fOtherNames.clear();
iter->second->fRequiredAttrs.clear();
iter->second->fAllowedAttrs.clear();
delete iter->second;
iter++;
}
fObjectClassSchema->clear();
DSDelete( fObjectClassSchema );
}
DSCFRelease( fRecordAttrMapDict );
DSCFRelease( fRecordTypeMapCFArray );
DSCFRelease( fAttrTypeMapCFArray );
DSDelete( fMapSearchBase );
DSCFRelease( fSASLmethods );
DSDelete( fKerberosId );
DSDelete( fConfigLock );
}
#pragma mark -
#pragma mark CLDAPv3Configs Class
CLDAPv3Configs::CLDAPv3Configs ( void )
{
fXMLData = nil;
pXMLConfigLock = new DSMutexSemaphore();
}
CLDAPv3Configs::~CLDAPv3Configs ( void )
{
fConfigMapMutex.Wait();
LDAPConfigDataMapI configIter = fConfigMap.begin();
while( configIter != fConfigMap.end() )
{
DSDelete( configIter->second );
configIter++;
}
fConfigMap.clear();
fConfigMapMutex.Signal();
DSDelete( pXMLConfigLock );
DSCFRelease( fXMLData );
}
sInt32 CLDAPv3Configs::Init( void )
{
sInt32 siResult = eDSNoErr;
sLDAPConfigData *pConfig = nil;
XMLConfigLock();
DSCFRelease( fXMLData );
siResult = ReadXMLConfig();
XMLConfigUnlock();
if (siResult == eDSNoErr)
{
fConfigMapMutex.Wait();
LDAPConfigDataMapI configIter = fConfigMap.begin();
while( configIter != fConfigMap.end() )
{
pConfig = configIter->second;
if (pConfig != nil)
{
pConfig->bUpdated = false;
}
configIter++;
}
fConfigMapMutex.Signal();
siResult = ConfigLDAPServers();
}
return( siResult );
}
#pragma mark -
#pragma mark Config File Operations
char *CLDAPv3Configs::CreatePrefFilename( void )
{
char *filenameString = NULL;
CFStringRef cfENetAddr = NULL;
GetMACAddress( &cfENetAddr, NULL, false );
if( cfENetAddr )
{
uInt32 linkAddrLen = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfENetAddr), kCFStringEncodingUTF8) + 1;
char *filenameBase = "/Library/Preferences/DirectoryService/DSLDAPv3PlugInConfig.";
int baseLen = strlen( filenameBase );
char *tempFilename = (char *) calloc( baseLen + linkAddrLen + 6 + 1, 1 ); struct stat statResult;
bcopy( filenameBase, tempFilename, baseLen );
CFStringGetCString( cfENetAddr, tempFilename + baseLen, linkAddrLen+1, kCFStringEncodingUTF8 );
strcat( tempFilename, ".plist" );
DSCFRelease(cfENetAddr);
if( ::stat(tempFilename, &statResult) == 0 )
{
filenameString = tempFilename;
}
else
{
DBGLOG1( kLogPlugin, "CLDAPv3Configs: Could not find a computer specific configuration file %s", tempFilename );
DSFreeString(tempFilename);
}
}
return ( filenameString ? filenameString : strdup("/Library/Preferences/DirectoryService/DSLDAPv3PlugInConfig.plist") );
}
sInt32 CLDAPv3Configs::ReadXMLConfig ( void )
{
sInt32 siResult = eDSNoErr;
CFURLRef configFileURL = NULL;
CFURLRef configFileCorruptedURL = NULL;
CFDataRef xmlData = NULL;
struct stat statResult;
bool bReadFile = false;
bool bCorruptedFile = false;
bool bWroteFile = false;
CFMutableDictionaryRef configDict = NULL;
sInt32 errorCode = 0;
CFStringRef sCorruptedPath = NULL;
char *filenameString = CreatePrefFilename();
CFStringRef sPath = NULL;
siResult = ::stat( filenameString, &statResult );
sPath = CFStringCreateWithCString( kCFAllocatorDefault, filenameString, kCFStringEncodingUTF8 );
if (sPath != NULL)
{
configFileURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sPath, kCFURLPOSIXPathStyle, false );
DSCFRelease( sPath );
if (siResult != eDSNoErr)
{
CreatePrefDirectory();
configDict = CFDictionaryCreateMutable( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( configDict, CFSTR( kXMLLDAPVersionKey ), CFSTR( "DSLDAPv3PlugIn Version 1.5" ) );
DBGLOG( kLogPlugin, "CLDAPv3Configs: Created a new LDAP XML config file since it did not exist" );
xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict);
if ( (configFileURL != NULL) && (xmlData != NULL) )
{
siResult = CFURLWriteDataAndPropertiesToResource( configFileURL,
xmlData,
NULL,
&errorCode);
}
DSCFRelease(configDict);
DSCFRelease(xmlData);
}
if ( (siResult == eDSNoErr) && (configFileURL != NULL) ) {
chmod( filenameString, S_IRUSR | S_IWUSR );
bReadFile = CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault,
configFileURL,
&xmlData, NULL,
NULL,
&siResult);
}
}
if (bReadFile)
{
fXMLData = xmlData;
if (!VerifyXML())
{
char *corruptPath = "/Library/Preferences/DirectoryService/DSLDAPv3PlugInConfigCorrupted.plist";
DBGLOG( kLogPlugin, "CLDAPv3Configs: LDAP XML config file is corrupted" );
bCorruptedFile = true;
sCorruptedPath = ::CFStringCreateWithCString( kCFAllocatorDefault, corruptPath, kCFStringEncodingUTF8 );
if (sCorruptedPath != NULL)
{
configFileCorruptedURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sCorruptedPath, kCFURLPOSIXPathStyle, false );
DSCFRelease( sCorruptedPath ); if (configFileCorruptedURL != NULL)
{
bWroteFile = CFURLWriteDataAndPropertiesToResource( configFileCorruptedURL,
xmlData,
NULL,
&errorCode);
if (bWroteFile)
{
chmod( corruptPath, S_IRUSR | S_IWUSR );
}
}
}
DSCFRelease(xmlData);
}
}
else {
DBGLOG( kLogPlugin, "CLDAPv3Configs: LDAP XML config file is unreadable" );
bCorruptedFile = true;
}
if (bCorruptedFile)
{
configDict = CFDictionaryCreateMutable( kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( configDict, CFSTR( kXMLLDAPVersionKey ), CFSTR( "DSLDAPv3PlugIn Version 1.5" ) );
DBGLOG( kLogPlugin, "CLDAPv3Configs: Writing a new LDAP XML config file" );
xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict);
fXMLData = xmlData;
if ( (configFileURL != NULL) && (xmlData != NULL) )
{
siResult = CFURLWriteDataAndPropertiesToResource( configFileURL,
xmlData,
NULL,
&errorCode);
if (siResult == eDSNoErr)
{
chmod( filenameString, S_IRUSR | S_IWUSR );
}
}
DSCFRelease(configDict);
}
if( fXMLData != NULL )
{
if( ConvertLDAPv2Config() )
{
siResult = CFURLWriteDataAndPropertiesToResource( configFileURL,
fXMLData,
NULL,
&errorCode);
if (siResult == eDSNoErr)
{
chmod( filenameString, S_IRUSR | S_IWUSR );
}
}
}
DSCFRelease(configFileURL);
DSCFRelease(configFileCorruptedURL);
DSFreeString( filenameString );
return( siResult );
}
sInt32 CLDAPv3Configs::WriteXMLConfig ( void )
{
sInt32 siResult = eDSNoErr;
CFURLRef configFileURL = NULL;
bool bWroteFile = false;
struct stat statResult;
sInt32 errorCode = 0;
char *filenameString = CreatePrefFilename();
while (!bWroteFile)
{
siResult = ::stat( filenameString, &statResult );
if (siResult != eDSNoErr)
{
CreatePrefDirectory();
}
CFStringRef sPath = CFStringCreateWithCString( kCFAllocatorDefault, filenameString, kCFStringEncodingUTF8 );
configFileURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sPath, kCFURLPOSIXPathStyle, false );
CFRelease( sPath );
XMLConfigLock();
if (fXMLData != nil)
{
bWroteFile = CFURLWriteDataAndPropertiesToResource( configFileURL,
fXMLData,
NULL,
&errorCode);
::chmod( filenameString, 0600 );
}
XMLConfigUnlock();
CFRelease(configFileURL); configFileURL = nil;
}
if (bWroteFile)
{
DBGLOG( kLogPlugin, "CLDAPv3Configs: Have written the LDAP XML config file:" );
DBGLOG1( kLogPlugin, "CLDAPv3Configs: %s", filenameString );
siResult = eDSNoErr;
}
else
{
DBGLOG( kLogPlugin, "CLDAPv3Configs: LDAP XML config file has NOT been written" );
DBGLOG( kLogPlugin, "CLDAPv3Configs: Update to LDAP Config File Failed" );
siResult = eDSPlugInConfigFileError;
}
DSFreeString( filenameString );
return( siResult );
}
sInt32 CLDAPv3Configs::SetXMLConfig ( CFDataRef xmlData )
{
CFDataRef currentXMLData = NULL;
sInt32 siResult = eDSInvalidPlugInConfigData;
XMLConfigLock();
currentXMLData = fXMLData;
CFRetain( xmlData );
fXMLData = xmlData;
if (VerifyXML())
{
DSCFRelease( currentXMLData );
siResult = WriteXMLConfig();
}
else
{
CFRelease( xmlData );
fXMLData = currentXMLData;
}
XMLConfigUnlock();
return(siResult);
}
CFDataRef CLDAPv3Configs::CopyXMLConfig ( void )
{
CFDataRef combinedConfigDataRef = NULL;
CFStringRef errorString = NULL;
CFMutableDictionaryRef configDict = NULL;
CFArrayRef configArray = NULL;
CFIndex configArrayCount = 0;
CFMutableArrayRef dhcpConfigArray = NULL;
sLDAPConfigData* pConfig = nil;
fConfigMapMutex.Wait();
LDAPConfigDataMapI configIter = fConfigMap.begin();
while( configIter != fConfigMap.end() )
{
pConfig = configIter->second;
if (pConfig != nil && pConfig->bUseAsDefaultLDAP ) {
bool isCurrentConfInXMLData = false;
CFStringRef curConfigServerName = CFStringCreateWithCString( NULL, pConfig->fServerName, kCFStringEncodingUTF8 );
if ( configDict == NULL )
{
XMLConfigLock();
configDict = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
fXMLData,
kCFPropertyListMutableContainers, NULL);
XMLConfigUnlock();
if ( configDict == NULL )
{
char errBuf[1024];
CFStringGetCString( errorString, errBuf, sizeof(errBuf), kCFStringEncodingUTF8 );
syslog(LOG_ALERT,"DSLDAPv3PlugIn: [%s] LDAP server config could not be read.", errBuf);
CFRelease( curConfigServerName );
curConfigServerName = NULL;
break;
}
if ( CFDictionaryGetTypeID() != CFGetTypeID( configDict ) )
{
syslog(LOG_ALERT,"DSLDAPv3PlugIn: LDAP server config could not be read as it was not in the correct format!");
CFRelease( configDict );
configDict = NULL;
CFRelease( curConfigServerName );
curConfigServerName = NULL;
break;
}
configArray = (CFArrayRef)CFDictionaryGetValue( configDict, CFSTR(kXMLConfigArrayKey) );
if ( configArray != NULL )
configArrayCount = CFArrayGetCount( configArray );
}
for ( CFIndex i=0; i<configArrayCount; i++ )
{
CFStringRef indexedServerName = (CFStringRef)CFDictionaryGetValue( (CFDictionaryRef)CFArrayGetValueAtIndex( configArray, i ), CFSTR(kXMLServerKey) );
if ( CFStringCompare( curConfigServerName, indexedServerName, 0 ) == kCFCompareEqualTo )
{
isCurrentConfInXMLData = true;
break;
}
}
if ( !isCurrentConfInXMLData )
{
if ( dhcpConfigArray == NULL )
dhcpConfigArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFMutableDictionaryRef curConfigDict = CFDictionaryCreateMutable( NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFNumberRef curConfigPort = CFNumberCreate( NULL, kCFNumberIntType, &(pConfig->fServerPort) );
CFStringRef curConfigUIName = CFStringCreateWithCString( NULL, pConfig->fUIName, kCFStringEncodingUTF8 );
CFNumberRef curConfigOpenCloseTimeOut = CFNumberCreate( NULL, kCFNumberIntType, &(pConfig->fOpenCloseTimeout) );
CFNumberRef curConfigSearchTimeOut = CFNumberCreate( NULL, kCFNumberIntType, &(pConfig->fSearchTimeout) );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLUserDefinedNameKey), curConfigUIName );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLServerKey), curConfigServerName );
if ( pConfig->fRecordTypeMapCFArray != NULL )
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLRecordTypeMapArrayKey), pConfig->fRecordTypeMapCFArray );
if ( pConfig->fAttrTypeMapCFArray != NULL )
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLAttrTypeMapArrayKey), pConfig->fAttrTypeMapCFArray );
if ( pConfig->fReplicaHostnames != NULL)
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLReplicaHostnameListArrayKey), pConfig->fReplicaHostnames );
if ( pConfig->fWriteableHostnames != NULL)
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLWriteableHostnameListArrayKey), pConfig->fWriteableHostnames );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLPortNumberKey), curConfigPort );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLOpenCloseTimeoutSecsKey), curConfigOpenCloseTimeOut );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLSearchTimeoutSecsKey), curConfigSearchTimeOut );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLIsSSLFlagKey), (pConfig->bIsSSL)?kCFBooleanTrue:kCFBooleanFalse );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLLDAPv2ReadOnlyKey), (pConfig->bLDAPv2ReadOnly)?kCFBooleanTrue:kCFBooleanFalse );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLMakeDefLDAPFlagKey), kCFBooleanTrue );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLEnableUseFlagKey), kCFBooleanTrue );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLServerMappingsFlagKey), (pConfig->bServerMappings)?kCFBooleanTrue:kCFBooleanFalse );
CFDictionaryAddValue( curConfigDict, CFSTR(kXMLReferralFlagKey), (pConfig->bReferrals)?kCFBooleanTrue:kCFBooleanFalse );
CFArrayAppendValue( dhcpConfigArray, curConfigDict );
CFRelease( curConfigSearchTimeOut );
CFRelease( curConfigOpenCloseTimeOut );
CFRelease( curConfigUIName );
CFRelease( curConfigPort );
CFRelease( curConfigDict );
}
CFRelease( curConfigServerName );
curConfigServerName = NULL;
}
configIter++;
}
fConfigMapMutex.Signal();
if ( dhcpConfigArray == NULL )
{
XMLConfigLock();
combinedConfigDataRef = fXMLData;
CFRetain( combinedConfigDataRef );
XMLConfigUnlock();
}
else
{
CFDictionaryAddValue( configDict, CFSTR(kXMLDHCPConfigArrayKey), dhcpConfigArray );
combinedConfigDataRef = CFPropertyListCreateXMLData( NULL, configDict );
}
if ( dhcpConfigArray )
CFRelease( dhcpConfigArray );
if ( configDict )
CFRelease( configDict );
return combinedConfigDataRef;
}
bool CLDAPv3Configs::VerifyXML ( void )
{
bool verified = false;
CFMutableDictionaryRef configPropertyList;
XMLConfigLock();
if (fXMLData != nil)
{
configPropertyList = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
fXMLData,
kCFPropertyListMutableContainersAndLeaves,
NULL);
if (configPropertyList != nil )
{
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;
}
}
else
{
verified = false;
}
}
}
}
if( bUpdated && verified )
{
CFDataRef xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configPropertyList );
if( xmlData != NULL )
{
CFRelease( fXMLData );
fXMLData = xmlData;
}
}
DSCFRelease(configPropertyList);
}
}
XMLConfigUnlock();
return( verified );
}
void CLDAPv3Configs::XMLConfigLock( void )
{
if (pXMLConfigLock != nil)
{
pXMLConfigLock->Wait();
}
}
void CLDAPv3Configs::XMLConfigUnlock( void )
{
if (pXMLConfigLock != nil)
{
pXMLConfigLock->Signal();
}
}
void CLDAPv3Configs::VerifyKerberosForRealm( char *inRealmName, char *inServer )
{
struct stat statResult;
char *pExistingConfig = NULL;
char pServer[255] = { 0, };
hostent *hostEntry = gethostbyname( inServer );
if ( hostEntry != NULL )
{
hostEntry = gethostbyaddr( hostEntry->h_addr_list[0], hostEntry->h_length, hostEntry->h_addrtype );
if ( hostEntry != NULL )
{
strlcpy( pServer, hostEntry->h_name, 255 );
if ( stat("/Library/Preferences/edu.mit.Kerberos", &statResult) == 0 )
{
FILE *pFile = fopen( "/Library/Preferences/edu.mit.Kerberos", "r" );
if (pFile != NULL)
{
pExistingConfig = (char *) calloc( sizeof(char), statResult.st_size + 768);
fread( pExistingConfig, statResult.st_size, sizeof(char), pFile );
fclose( pFile );
}
}
if ( pExistingConfig != NULL && strstr(pExistingConfig, inRealmName) == NULL )
{
char *pRealmSection = strstr(pExistingConfig, "[realms]");
if ( pRealmSection != NULL )
{
char newSection[512] = { 0, };
int newSectionLen = 0;
snprintf( newSection, 512, "\t%s = {\n\t\tkdc = %s\n\t}\n", inRealmName, pServer );
newSectionLen = strlen( newSection );
pRealmSection = strchr( pRealmSection, '\n' ) + 1;
bcopy( pRealmSection, pRealmSection + newSectionLen, strlen(pRealmSection) );
bcopy( newSection, pRealmSection, newSectionLen );
char *pDomRealmSection = strstr(pExistingConfig, "[domain_realm]");
if ( pDomRealmSection != NULL )
{
char newSection2[256] = { 0, };
int newSection2Len = 0;
pDomRealmSection = strchr( pDomRealmSection, '\n' ) + 1;
snprintf( newSection2, 256, "\t%s = %s\n", pServer, inRealmName );
newSection2Len = strlen( newSection2 );
bcopy( pDomRealmSection, pDomRealmSection + newSection2Len, strlen(pDomRealmSection) );
bcopy( newSection2, pDomRealmSection, newSection2Len );
}
else
{
strcat( pExistingConfig, "[domain_realm]\n\t" );
strcat( pExistingConfig, pServer );
strcat( pExistingConfig, " = " );
strcat( pExistingConfig, inRealmName );
strcat( pExistingConfig, "\n" );
}
FILE *pFile = fopen( "/Library/Preferences/edu.mit.Kerberos", "w" );
if( pFile != NULL )
{
fwrite( pExistingConfig, 1, strlen(pExistingConfig), pFile );
fclose( pFile );
DBGLOG1( kLogPlugin, "CLDAPv3Configs: Updated edu.mit.Kerberos file with realm %s.", inRealmName );
}
else
{
syslog( LOG_INFO, "CLDAPv3Configs: Unable to update edu.mit.Kerberos file with realm %s.", inRealmName );
DBGLOG1( kLogPlugin, "CLDAPv3Configs: Unable to update edu.mit.Kerberos file with realm %s.", inRealmName );
}
}
else
{
DBGLOG1( kLogPlugin, "CLDAPv3Configs: edu.mit.Kerberos does not contain [realms] section.", inRealmName );
DSFreeString( pExistingConfig ); }
}
if ( pExistingConfig == NULL )
{
register int childPID = -1;
int nStatus;
DBGLOG1( kLogPlugin, "CLDAPv3Configs: Launching kerberosautoconfig because %s realm is missing.", inRealmName );
switch ( childPID = ::fork() )
{
case -1:
syslog( LOG_INFO, "CLDAPv3Configs: Couldn't launch kerberosautoconfig fork failed." );
DBGLOG( kLogPlugin, "CLDAPv3Configs: Couldn't launch kerberosautoconfig fork failed." );
break;
case 0:
execl( "/sbin/kerberosautoconfig", "kerberosautoconfig", "-r", inRealmName, "-m", pServer, NULL );
_exit(0);
break;
default:
while( ::waitpid( childPID, &nStatus, 0 ) == -1 && errno != ECHILD );
break;
}
}
}
}
DSFreeString( pExistingConfig );
}
#pragma mark -
#pragma mark Config Map Access Routines
void CLDAPv3Configs::DeleteConfigFromMap( char *inConfigNodename )
{
sLDAPConfigData *pConfig = nil;
bool bDeleteConfig = false;
if (inConfigNodename == NULL) return;
fConfigMapMutex.Wait();
LDAPConfigDataMapI configIter = fConfigMap.find( string(inConfigNodename) );
if( configIter != fConfigMap.end() )
{
pConfig = configIter->second;
fConfigMap.erase( string(inConfigNodename) );
if (pConfig->fRefCount <= 0)
{
bDeleteConfig = true;
}
else
{
pConfig->bMarkToDelete = true;
}
}
fConfigMapMutex.Signal();
if ( bDeleteConfig )
{
DSDelete( pConfig );
}
}
sLDAPConfigData *CLDAPv3Configs::ConfigWithNodeNameLock( char *inConfigName )
{
sLDAPConfigData *pConfig = nil;
if( inConfigName )
{
fConfigMapMutex.Wait();
LDAPConfigDataMapI configIter = fConfigMap.find( string(inConfigName) );
if( configIter != fConfigMap.end() )
{
pConfig = configIter->second;
pConfig->fRefCount++;
}
fConfigMapMutex.Signal();
if (pConfig != NULL)
{
pConfig->fConfigLock->Wait();
}
}
return pConfig;
}
void CLDAPv3Configs::ConfigUnlock( sLDAPConfigData *inConfig )
{
bool bDeleteConfig = false;
if (inConfig != NULL)
{
fConfigMapMutex.Wait();
inConfig->fRefCount--;
if ( (inConfig->bMarkToDelete) && (inConfig->fRefCount <= 0) )
{
fConfigMap.erase( string(inConfig->fNodeName) );
bDeleteConfig = true;
}
fConfigMapMutex.Signal();
inConfig->fConfigLock->Signal();
if ( bDeleteConfig )
{
DSDelete( inConfig );
}
}
}
#pragma mark -
#pragma mark Updating Configuration
sInt32 CLDAPv3Configs::UpdateReplicaList(char *inServerName, CFMutableArrayRef inReplicaHostnames, CFMutableArrayRef inWriteableHostnames)
{
sInt32 siResult = eDSNoErr;
CFPropertyListRef configPropertyList = NULL;
CFMutableDictionaryRef configDict = NULL;
CFArrayRef cfArrayRef = NULL;
CFIndex cfConfigCount = 0;
CFDataRef xmlData = NULL;
bool bDoWrite = false;
XMLConfigLock();
if (fXMLData != nil)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
fXMLData,
kCFPropertyListMutableContainersAndLeaves, NULL);
XMLConfigUnlock();
if (configPropertyList != nil )
{
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
configDict = (CFMutableDictionaryRef) configPropertyList;
}
if (configDict != nil)
{
cfArrayRef = nil;
cfArrayRef = (CFArrayRef) CFDictionaryGetValue( configDict, CFSTR( kXMLConfigArrayKey ) );
if (cfArrayRef != nil)
{
cfConfigCount = ::CFArrayGetCount( cfArrayRef );
for (sInt32 iConfigIndex = 0; iConfigIndex < cfConfigCount; iConfigIndex++)
{
CFMutableDictionaryRef serverDict = nil;
serverDict = (CFMutableDictionaryRef)::CFArrayGetValueAtIndex( cfArrayRef, iConfigIndex );
if ( serverDict != nil )
{
CFStringRef aString = (CFStringRef)CFDictionaryGetValue( serverDict, CFSTR( kXMLServerKey ) );
if ( aString != nil && CFGetTypeID( aString ) == CFStringGetTypeID() )
{
CFStringRef aServerName = CFStringCreateWithCString( NULL, inServerName, kCFStringEncodingUTF8 );
if (CFStringCompare(aString, aServerName, 0) == kCFCompareEqualTo)
{
CFArrayRef cfRepArrayRef = NULL;
cfRepArrayRef = (CFArrayRef) CFDictionaryGetValue( serverDict, CFSTR( kXMLReplicaHostnameListArrayKey ) );
if (cfRepArrayRef != NULL)
{
CFDictionaryRemoveValue( serverDict, CFSTR( kXMLReplicaHostnameListArrayKey ) );
}
if( inReplicaHostnames )
{
CFDictionarySetValue( serverDict, CFSTR( kXMLReplicaHostnameListArrayKey ), (CFArrayRef)inReplicaHostnames );
}
bDoWrite = true;
cfRepArrayRef = (CFArrayRef) CFDictionaryGetValue( serverDict, CFSTR( kXMLWriteableHostnameListArrayKey ) );
if (cfRepArrayRef != NULL)
{
CFDictionaryRemoveValue( serverDict, CFSTR( kXMLWriteableHostnameListArrayKey ) );
}
if( inWriteableHostnames )
{
CFDictionarySetValue( serverDict, CFSTR( kXMLWriteableHostnameListArrayKey ), (CFArrayRef)inWriteableHostnames );
}
bDoWrite = true;
if (bDoWrite)
{
xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict);
siResult = SetXMLConfig(xmlData);
CFRelease(xmlData);
xmlData = nil;
}
CFRelease(aServerName);
break; }
CFRelease(aServerName);
}
}
}
}
}
CFRelease(configPropertyList); configPropertyList = nil;
} } else
{
XMLConfigUnlock();
}
return( siResult );
}
sInt32 CLDAPv3Configs::UpdateConfigWithSecuritySettings( char *inNodeName, sLDAPConfigData *inConfig, LDAP *inLD )
{
sInt32 siResult = eDSNodeNotFound;
LDAPMessage *pLDAPResult = NULL;
timeval stTimeout = { 20, 0 }; bool bChangedPolicy = false;
bool bChangedConfig = false;
CFMutableDictionaryRef cfXMLDict = NULL;
if( inNodeName == NULL ) return eDSNullParameter;
XMLConfigLock();
if (fXMLData != NULL)
{
cfXMLDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, fXMLData, kCFPropertyListMutableContainersAndLeaves, NULL );
}
XMLConfigUnlock();
CFArrayRef cfConfigArray = (CFArrayRef) CFDictionaryGetValue( cfXMLDict, CFSTR(kXMLConfigArrayKey) );
CFIndex iCount = cfConfigArray ? CFArrayGetCount( cfConfigArray ) : 0;
CFMutableDictionaryRef cfConfigDict = NULL;
CFStringRef cfServerName = CFStringCreateWithCString( kCFAllocatorDefault, inNodeName, kCFStringEncodingUTF8 );
for( CFIndex ii = 0; ii < iCount; ii++ )
{
CFMutableDictionaryRef cfTempDict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( cfConfigArray, ii );
CFStringRef cfServer = (CFStringRef) CFDictionaryGetValue( cfTempDict, CFSTR(kXMLServerKey) );
if( CFStringCompare(cfServer, cfServerName, 0) == kCFCompareEqualTo )
{
cfConfigDict = cfTempDict;
break;
}
}
DSCFRelease( cfServerName );
if( cfConfigDict )
{
char *pAttribute = ExtractAttrMap( kDSStdRecordTypeConfig, kDS1AttrXMLPlist, inConfig->fRecordAttrMapDict, 1 );
if( pAttribute != NULL )
{
int iLDAPRetCode = ldap_search_ext_s( inLD, inConfig->fMapSearchBase, LDAP_SCOPE_SUBTREE, "(cn=macosxodpolicy)", NULL, false, NULL, NULL, &stTimeout, 0, &pLDAPResult );
if( iLDAPRetCode == LDAP_SUCCESS )
{
berval **pBValues = NULL;
if( (pBValues = ldap_get_values_len(inLD, pLDAPResult, pAttribute)) != NULL )
{
CFDataRef cfXMLData = CFDataCreate( kCFAllocatorDefault, (UInt8 *)(pBValues[0]->bv_val), pBValues[0]->bv_len );
if( cfXMLData != NULL )
{
CFMutableDictionaryRef cfTempDict = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, cfXMLData, kCFPropertyListMutableContainersAndLeaves, NULL );
if( cfTempDict )
{
CFDictionaryRef cfConfigPolicy = (CFDictionaryRef) CFDictionaryGetValue( cfTempDict, CFSTR(kXMLConfiguredSecurityKey) );
uInt32 iSecurityLevel = inConfig->fSecurityLevelLoc | CalculateSecurityPolicy( cfConfigPolicy );
if( inConfig->fSecurityLevel != iSecurityLevel )
{
inConfig->fSecurityLevel = iSecurityLevel;
bChangedPolicy = bChangedConfig = true;
}
CFBooleanRef cfBindingActive = (CFBooleanRef) CFDictionaryGetValue( cfTempDict, CFSTR(kXMLDirectoryBindingKey) );
if( cfBindingActive != NULL && CFGetTypeID(cfBindingActive) == CFBooleanGetTypeID() )
{
CFDictionarySetValue( cfConfigDict, CFSTR(kXMLDirectoryBindingKey), cfBindingActive );
bChangedConfig = true; }
CFRelease( cfTempDict );
cfTempDict = NULL;
}
CFRelease( cfXMLData ); cfXMLData = NULL;
}
ldap_value_free_len( pBValues );
pBValues = NULL;
}
}
if( pLDAPResult )
{
ldap_msgfree( pLDAPResult );
pLDAPResult = NULL;
}
free( pAttribute );
}
if( inConfig->fSASLmethods && CFArrayGetCount(inConfig->fSASLmethods) )
{
CFMutableDictionaryRef cfSupportedSecLevel = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( cfConfigDict, CFSTR(kXMLSupportedSecurityKey), cfSupportedSecLevel );
if( inConfig->bIsSSL )
{
CFDictionarySetValue( cfSupportedSecLevel, CFSTR(kXMLSecurityNoClearTextAuths), kCFBooleanTrue );
CFDictionarySetValue( cfSupportedSecLevel, CFSTR(kXMLSecurityPacketEncryption), kCFBooleanTrue );
}
CFRange stRange = CFRangeMake( 0, CFArrayGetCount(inConfig->fSASLmethods) );
if( CFArrayContainsValue( inConfig->fSASLmethods, stRange, CFSTR("CRAM-MD5")) )
{
CFDictionarySetValue( cfSupportedSecLevel, CFSTR(kXMLSecurityNoClearTextAuths), kCFBooleanTrue );
}
if( CFArrayContainsValue( inConfig->fSASLmethods, stRange, CFSTR("GSSAPI")) )
{
CFDictionarySetValue( cfSupportedSecLevel, CFSTR(kXMLSecurityNoClearTextAuths), kCFBooleanTrue );
CFDictionarySetValue( cfSupportedSecLevel, CFSTR(kXMLSecurityManInTheMiddle), kCFBooleanTrue );
CFDictionarySetValue( cfSupportedSecLevel, CFSTR(kXMLSecurityPacketSigning), kCFBooleanTrue );
CFDictionarySetValue( cfSupportedSecLevel, CFSTR(kXMLSecurityPacketEncryption), kCFBooleanTrue );
}
bChangedConfig = true;
DSCFRelease(cfSupportedSecLevel);
}
else if( CFDictionaryContainsKey(cfConfigDict, CFSTR(kXMLSupportedSecurityKey)) )
{
CFDictionaryRemoveValue( cfConfigDict, CFSTR(kXMLSupportedSecurityKey) );
bChangedConfig = true;
}
if( bChangedConfig )
{
CFDataRef aXMLData = (CFDataRef) CFPropertyListCreateXMLData( kCFAllocatorDefault, cfXMLDict );
SetXMLConfig( aXMLData );
DSCFRelease( aXMLData );
if( bChangedPolicy )
{
siResult = eDSNoErr; DBGLOG1( kLogPlugin, "CLDAPv3Configs: [%s] Updated Security Policies from Directory.", inConfig->fNodeName );
syslog(LOG_ALERT,"LDAPv3: [%s] Updated Security Policies from Directory.", inConfig->fNodeName);
}
}
}
inConfig->bGetSecuritySettings = false;
DSCFRelease( cfXMLDict );
return siResult;
}
sInt32 CLDAPv3Configs::UpdateLDAPConfigWithServerMappings ( char *inServer, char *inMapSearchBase, int inPortNumber, bool inIsSSL, bool inLDAPv2ReadOnly, bool inMakeDefLDAP, bool inReferrals, LDAP *inServerHost)
{
sInt32 siResult = eDSNoErr;
CFDataRef ourXMLData = nil;
CFDataRef newXMLData = nil;
ourXMLData = RetrieveServerMappings( inServer, inMapSearchBase, inPortNumber, inIsSSL, inLDAPv2ReadOnly, inServerHost );
if (ourXMLData != nil)
{
newXMLData = VerifyAndUpdateServerLocation(inServer, inPortNumber, inIsSSL, inLDAPv2ReadOnly, inMakeDefLDAP, ourXMLData);
if (newXMLData != nil)
{
CFRelease(ourXMLData);
ourXMLData = newXMLData;
newXMLData = nil;
}
siResult = AddLDAPServer(ourXMLData);
CFRelease(ourXMLData);
if (siResult != eDSNoErr)
{
syslog(LOG_ALERT,"DSLDAPv3PlugIn: [%s] LDAP server config not updated with server mappings due to server mappings format error.", inServer);
}
}
else
{
syslog(LOG_ALERT,"DSLDAPv3PlugIn: [%s] LDAP server config not updated with server mappings due to server mappings error.", inServer);
siResult = eDSCannotAccessSession;
}
return(siResult);
}
CFDataRef CLDAPv3Configs::VerifyAndUpdateServerLocation( char *inServer, int inPortNumber, bool inIsSSL, bool inLDAPv2ReadOnly, bool inMakeDefLDAP, CFDataRef inXMLData )
{
CFPropertyListRef configPropertyList = nil;
CFMutableDictionaryRef serverConfigDict = nil;
char *configVersion = nil;
int portNumber = 389;
bool bIsSSL = false;
bool bLDAPv2ReadOnly = false;
CFStringRef cfStringRef = nil;
bool bUpdate = false;
CFBooleanRef cfBool = false;
CFNumberRef cfNumber = 0;
CFDataRef outXMLData = nil;
bool bIsSrvrMappings = false;
bool bIsDefLDAP = false;
if (inXMLData != nil)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inXMLData,
kCFPropertyListMutableContainers,
NULL);
if (configPropertyList != nil )
{
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
serverConfigDict = (CFMutableDictionaryRef) configPropertyList; }
if (serverConfigDict != nil)
{
configVersion = GetVersion(serverConfigDict);
if ( configVersion == nil )
{
CFRelease(configPropertyList); configPropertyList = nil;
return nil;
}
else
{
DBGLOG( kLogPlugin, "CLDAPv3Configs: Have successfully read the LDAP XML config data" );
if (strcmp(configVersion,"DSLDAPv3PlugIn Version 1.5") == 0)
{
cfStringRef = (CFStringRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLServerKey ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
CFStringRef cfInServer = CFStringCreateWithCString(kCFAllocatorDefault, inServer, kCFStringEncodingUTF8);
if( CFStringCompare(cfStringRef, cfInServer, 0) != kCFCompareEqualTo )
{
bUpdate = true;
CFDictionaryReplaceValue(serverConfigDict, CFSTR( kXMLServerKey ), cfInServer);
CFRelease(cfInServer);
cfInServer = nil;
}
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLPortNumberKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &portNumber);
if (portNumber != inPortNumber)
{
bUpdate = true;
cfNumber = CFNumberCreate(NULL,kCFNumberIntType,&inPortNumber);
CFDictionaryReplaceValue(serverConfigDict, CFSTR( kXMLPortNumberKey ), cfNumber);
CFRelease(cfNumber);
cfNumber = 0;
}
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLIsSSLFlagKey ) );
if (cfBool != nil)
{
bIsSSL = CFBooleanGetValue( cfBool );
if (bIsSSL != inIsSSL)
{
bUpdate = true;
CFDictionaryReplaceValue(serverConfigDict, CFSTR( kXMLIsSSLFlagKey ), (inIsSSL ? kCFBooleanTrue : kCFBooleanFalse) ); }
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLLDAPv2ReadOnlyKey ) );
if (cfBool != nil)
{
bLDAPv2ReadOnly = CFBooleanGetValue( cfBool );
if (bLDAPv2ReadOnly != inLDAPv2ReadOnly)
{
bUpdate = true;
CFDictionaryReplaceValue(serverConfigDict, CFSTR( kXMLLDAPv2ReadOnlyKey ), (inLDAPv2ReadOnly ? kCFBooleanTrue : kCFBooleanFalse) ); }
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLServerMappingsFlagKey ) );
if (cfBool != nil)
{
bIsSrvrMappings = CFBooleanGetValue( cfBool );
if (!bIsSrvrMappings)
{
bUpdate = true;
CFDictionaryReplaceValue(serverConfigDict, CFSTR( kXMLServerMappingsFlagKey ), kCFBooleanTrue);
}
}
else
{
bUpdate = true;
CFDictionarySetValue(serverConfigDict, CFSTR( kXMLServerMappingsFlagKey ), kCFBooleanTrue); }
cfBool = (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLMakeDefLDAPFlagKey ) );
if (cfBool != nil)
{
bIsDefLDAP = CFBooleanGetValue( cfBool );
if (!bIsDefLDAP && inMakeDefLDAP)
{
bUpdate = true;
CFDictionaryReplaceValue(serverConfigDict, CFSTR( kXMLMakeDefLDAPFlagKey ), kCFBooleanTrue);
}
else if (bIsDefLDAP && !inMakeDefLDAP)
{
bUpdate = true;
CFDictionaryReplaceValue(serverConfigDict, CFSTR( kXMLMakeDefLDAPFlagKey ), kCFBooleanFalse);
}
}
else
{
bUpdate = true;
CFDictionarySetValue(serverConfigDict, CFSTR( kXMLMakeDefLDAPFlagKey ), (inMakeDefLDAP ? kCFBooleanTrue : kCFBooleanFalse));
}
if (bUpdate)
{
outXMLData = CFPropertyListCreateXMLData( kCFAllocatorDefault, serverConfigDict);
}
}
delete(configVersion);
} }
CFRelease(configPropertyList); configPropertyList = nil;
} }
return( outXMLData );
}
sInt32 CLDAPv3Configs::ConfigLDAPServers ( void )
{
sInt32 siResult = eDSNoErr;
CFPropertyListRef configPropertyList = NULL;
CFMutableDictionaryRef configDict = NULL;
CFArrayRef cfArrayRef = NULL;
CFIndex cfConfigCount = 0;
CFDataRef xmlData = NULL;
char *configVersion = nil;
try
{
XMLConfigLock();
if (fXMLData != nil)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
fXMLData,
kCFPropertyListMutableContainers, NULL );
XMLConfigUnlock();
if (configPropertyList != nil )
{
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
configDict = (CFMutableDictionaryRef) configPropertyList;
}
if (configDict != nil)
{
configVersion = GetVersion(configDict);
if ( configVersion == nil ) throw( (sInt32)eDSVersionMismatch ); if (configVersion != nil)
{
DBGLOG( kLogPlugin, "CLDAPv3Configs: Have successfully read the LDAP XML config file" );
if (strcmp(configVersion,"DSLDAPv3PlugIn Version 1.5") == 0)
{
}
else
{
CFDictionaryRemoveValue( configDict, CFSTR( kXMLLDAPVersionKey ) );
CFDictionarySetValue( configDict, CFSTR( kXMLLDAPVersionKey ), CFSTR( "DSLDAPv3PlugIn Version 1.5" ) );
xmlData = CFPropertyListCreateXMLData( kCFAllocatorDefault, configDict);
siResult = SetXMLConfig(xmlData);
CFRelease(xmlData);
xmlData = nil;
}
cfArrayRef = (CFArrayRef) CFDictionaryGetValue( configDict, CFSTR( kXMLConfigArrayKey ) );
if (cfArrayRef != nil)
{
cfConfigCount = ::CFArrayGetCount( cfArrayRef );
for (sInt32 iConfigIndex = 0; iConfigIndex < cfConfigCount; iConfigIndex++)
{
CFDictionaryRef serverConfigDict = (CFDictionaryRef)::CFArrayGetValueAtIndex( cfArrayRef, iConfigIndex );
if ( serverConfigDict != nil )
{
siResult = MakeLDAPConfig( serverConfigDict, true );
}
}
} delete(configVersion);
}
}
} } else
{
XMLConfigUnlock();
}
} catch ( sInt32 err )
{
siResult = err;
}
if (configPropertyList != nil)
{
CFRelease(configPropertyList);
configPropertyList = nil;
}
return( siResult );
}
sInt32 CLDAPv3Configs::AddToConfig ( CFDataRef inXMLData )
{
sInt32 siResult = eDSCorruptBuffer;
CFPropertyListRef configPropertyList = NULL;
CFMutableDictionaryRef configDict = NULL;
CFStringRef cfStringRef = NULL;
CFBooleanRef cfBool = false;
CFNumberRef cfNumber = 0;
char *server = nil;
char *mapSearchBase = nil;
int portNumber = 389;
bool bIsSSL = false;
bool bLDAPv2ReadOnly = false;
bool bServerMappings = false;
bool bUseConfig = false;
bool bReferrals = true;
int opencloseTO = kLDAPDefaultOpenCloseTimeoutInSeconds;
int idleTO = 2;
int delayRebindTry = kLDAPDefaultRebindTryTimeoutInSeconds;
int searchTO = kLDAPDefaultSearchTimeoutInSeconds;
CFPropertyListRef xConfigPropertyList = NULL;
CFMutableDictionaryRef xConfigDict = NULL;
CFMutableArrayRef cfMutableArrayRef = NULL;
CFDataRef xmlBlob = NULL;
if (inXMLData != nil)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inXMLData,
kCFPropertyListMutableContainers, NULL);
if (configPropertyList != nil )
{
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
configDict = (CFMutableDictionaryRef) configPropertyList;
}
if (configDict != nil)
{
CFDictionarySetValue(configDict, CFSTR( kXMLMakeDefLDAPFlagKey ), kCFBooleanTrue);
XMLConfigLock();
if (fXMLData != nil)
{
xConfigPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
fXMLData,
kCFPropertyListMutableContainers, NULL);
XMLConfigUnlock();
if (xConfigPropertyList != nil && CFDictionaryGetTypeID() == CFGetTypeID( xConfigPropertyList ) )
{
xConfigDict = (CFMutableDictionaryRef) xConfigPropertyList;
if ( CFDictionaryContainsKey( xConfigDict, CFSTR( kXMLConfigArrayKey ) ) )
{
cfMutableArrayRef = (CFMutableArrayRef)CFDictionaryGetValue( xConfigDict, CFSTR( kXMLConfigArrayKey ) );
CFArrayAppendValue(cfMutableArrayRef, configDict);
}
else {
cfMutableArrayRef = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(cfMutableArrayRef, configDict);
CFDictionarySetValue( xConfigDict, CFSTR( kXMLConfigArrayKey ), cfMutableArrayRef );
CFRelease(cfMutableArrayRef);
}
xmlBlob = CFPropertyListCreateXMLData( kCFAllocatorDefault, xConfigDict);
SetXMLConfig(xmlBlob);
CFRelease(xmlBlob);
xmlBlob = nil;
}
if( xConfigPropertyList )
{
CFRelease(xConfigPropertyList);
xConfigPropertyList = NULL;
}
} else
{
XMLConfigUnlock();
}
cfBool = (CFBooleanRef)CFDictionaryGetValue( configDict, CFSTR( kXMLEnableUseFlagKey ) );
if (cfBool != nil)
{
bUseConfig = CFBooleanGetValue( cfBool );
}
if ( bUseConfig )
{
cfStringRef = (CFStringRef)CFDictionaryGetValue( configDict, CFSTR( kXMLServerKey ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
server = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, server, uiLength, kCFStringEncodingUTF8 );
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( configDict, CFSTR( kXMLIsSSLFlagKey ) );
if (cfBool != nil)
{
bIsSSL = CFBooleanGetValue( cfBool );
if (bIsSSL)
{
portNumber = LDAPS_PORT; }
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( configDict, CFSTR( kXMLLDAPv2ReadOnlyKey ) );
if (cfBool != nil)
{
bLDAPv2ReadOnly = CFBooleanGetValue( cfBool );
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( configDict, CFSTR( kXMLOpenCloseTimeoutSecsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &opencloseTO);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( configDict, CFSTR( kXMLIdleTimeoutMinsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &idleTO);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( configDict, CFSTR( kXMLDelayedRebindTrySecsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &delayRebindTry);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( configDict, CFSTR( kXMLSearchTimeoutSecsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &searchTO);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( configDict, CFSTR( kXMLPortNumberKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &portNumber);
}
cfBool = (CFBooleanRef)CFDictionaryGetValue( configDict, CFSTR( kXMLServerMappingsFlagKey ) );
if (cfBool != nil)
{
bServerMappings = CFBooleanGetValue( cfBool );
}
cfBool = (CFBooleanRef)CFDictionaryGetValue( configDict, CFSTR( kXMLReferralFlagKey ) );
if (cfBool != nil)
{
bReferrals = CFBooleanGetValue( cfBool );
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( configDict, CFSTR( kXMLMapSearchBase ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
mapSearchBase = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, mapSearchBase, uiLength, kCFStringEncodingUTF8 );
}
siResult = MakeServerBasedMappingsLDAPConfig( server, mapSearchBase, opencloseTO, idleTO, delayRebindTry, searchTO, portNumber, bIsSSL, true, bReferrals, bLDAPv2ReadOnly );
if ( server != nil )
{
free( server );
server = nil;
}
if ( mapSearchBase != nil )
{
free( mapSearchBase );
mapSearchBase = nil;
}
}
}
CFRelease(configPropertyList);
}
}
return(siResult);
}
sInt32 CLDAPv3Configs::AddLDAPServer( CFDataRef inXMLData )
{
sInt32 siResult = eDSNoErr;
CFPropertyListRef configPropertyList = nil;
CFMutableDictionaryRef serverConfigDict = nil;
char *configVersion = nil;
try
{
if (inXMLData != nil)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inXMLData,
kCFPropertyListMutableContainers,
NULL);
if (configPropertyList != nil && CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ))
{
serverConfigDict = (CFMutableDictionaryRef) configPropertyList;
configVersion = GetVersion(serverConfigDict);
if ( configVersion == nil )
{
syslog(LOG_ALERT,"LDAPv3: Obtained LDAP server mappings is missing the version string.");
throw( (sInt32)eDSVersionMismatch ); }
else
{
DBGLOG( kLogPlugin, "CLDAPv3Configs: Have successfully read the LDAP XML config data" );
if (strcmp(configVersion,"DSLDAPv3PlugIn Version 1.5") == 0)
{
siResult = MakeLDAPConfig(serverConfigDict, false, true);
}
else
{
syslog(LOG_ALERT,"LDAPv3: Obtained LDAP server mappings contain incorrect version string [%s] instead of [DSLDAPv3PlugIn Version 1.5].", configVersion);
}
delete(configVersion);
} } }
} catch ( sInt32 err )
{
siResult = err;
}
if (configPropertyList != nil)
{
CFRelease(configPropertyList); configPropertyList = nil;
}
return( siResult );
}
#pragma mark -
#pragma mark ConfigData Manipulation Routines
char** CLDAPv3Configs::GetDefaultLDAPNodeStrings( uInt32 &count )
{
uInt32 counter = 0;
sLDAPConfigData *pConfig = nil;
fConfigMapMutex.Wait();
LDAPConfigDataMapI configIter = fConfigMap.begin();
while( configIter != fConfigMap.end() )
{
pConfig = configIter->second;
if ( (pConfig != nil) && (pConfig->bUseAsDefaultLDAP) && (pConfig->fServerName != nil) )
{
counter++;
}
configIter++;
}
count = counter;
char** outList = (char **)calloc(counter + 1, sizeof(char*));
configIter = fConfigMap.begin();
counter = 0;
while( configIter != fConfigMap.end() )
{
pConfig = configIter->second;
if ( (pConfig != nil) && (pConfig->bUseAsDefaultLDAP) && (pConfig->fServerName != nil) )
{
char *theDHCPNodeName = (char *) calloc(1, sizeof("/LDAPv3/") + strlen(pConfig->fServerName));
strcpy(theDHCPNodeName, "/LDAPv3/");
strcat(theDHCPNodeName, pConfig->fServerName);
outList[counter] = theDHCPNodeName;
counter++;
}
configIter++;
}
fConfigMapMutex.Signal();
return(outList);
}
void CLDAPv3Configs::SetAllConfigBuildReplicaFlagTrue( void )
{
fConfigMapMutex.Wait();
LDAPConfigDataMapI configIter = fConfigMap.begin();
while( configIter != fConfigMap.end() )
{
sLDAPConfigData *pConfig = configIter->second;
if (pConfig != nil)
{
pConfig->bBuildReplicaList = true;
}
configIter++;
}
fConfigMapMutex.Signal();
}
uInt32 CLDAPv3Configs::CalculateSecurityPolicy( CFDictionaryRef inConfiguration )
{
CFBooleanRef cfBool;
uInt32 uiSecurityLevel = kSecNoSecurity;
if ( inConfiguration != NULL && CFGetTypeID(inConfiguration) == CFDictionaryGetTypeID() )
{
if( (cfBool = (CFBooleanRef) CFDictionaryGetValue(inConfiguration, CFSTR(kXMLSecurityNoClearTextAuths))) && CFBooleanGetValue(cfBool) )
{
uiSecurityLevel |= kSecDisallowCleartext;
}
if( (cfBool = (CFBooleanRef) CFDictionaryGetValue(inConfiguration, CFSTR(kXMLSecurityManInTheMiddle))) && CFBooleanGetValue(cfBool) )
{
uiSecurityLevel |= kSecManInMiddle;
}
if( (cfBool = (CFBooleanRef) CFDictionaryGetValue(inConfiguration, CFSTR(kXMLSecurityPacketSigning))) && CFBooleanGetValue(cfBool) )
{
uiSecurityLevel |= kSecPacketSigning;
}
if( (cfBool = (CFBooleanRef) CFDictionaryGetValue(inConfiguration, CFSTR(kXMLSecurityPacketEncryption))) && CFBooleanGetValue(cfBool) )
{
uiSecurityLevel |= kSecPacketEncryption;
}
}
return uiSecurityLevel;
}
sInt32 CLDAPv3Configs::MakeLDAPConfig( CFDictionaryRef ldapDict, bool inOverWriteAll, bool inServerMappingUpdate )
{
sInt32 siResult = eDSNoErr;
CFStringRef cfStringRef = nil;
CFDataRef cfDataRef = nil;
CFBooleanRef cfBool = false;
CFNumberRef cfNumber = nil;
char *server = nil;
sLDAPConfigData *pConfig = nil;
bool bUseConfig = false;
cfBool = (CFBooleanRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLEnableUseFlagKey ) );
if (cfBool != nil)
{
bUseConfig = CFBooleanGetValue( cfBool );
}
if ( bUseConfig )
{
cfStringRef = (CFStringRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLServerKey ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
server = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, server, uiLength, kCFStringEncodingUTF8 );
}
if( server != NULL && strlen(server) )
{
pConfig = ConfigWithNodeNameLock( server );
if( pConfig == NULL )
{
pConfig = new sLDAPConfigData;
pConfig->fServerName = server;
pConfig->fNodeName = strdup( server );
pConfig->fRefCount = 1;
fConfigMapMutex.Wait();
fConfigMap[string(pConfig->fNodeName)] = pConfig;
fConfigMapMutex.Signal();
pConfig->fConfigLock->Wait();
server = NULL; }
if( inOverWriteAll )
{
pConfig->bIsSSL = false;
pConfig->bLDAPv2ReadOnly = false;
pConfig->fServerPort = LDAP_PORT;
pConfig->fOpenCloseTimeout = kLDAPDefaultOpenCloseTimeoutInSeconds;
pConfig->fIdleTimeout = 2;
pConfig->fDelayRebindTry = kLDAPDefaultRebindTryTimeoutInSeconds;
pConfig->fSearchTimeout = kLDAPDefaultSearchTimeoutInSeconds;
pConfig->bSecureUse = false;
pConfig->bUseAsDefaultLDAP = false;
pConfig->bServerMappings = false;
pConfig->bReferrals = true;
pConfig->bDNSReplicas = false;
DSDelete( pConfig->fUIName );
DSDelete( pConfig->fServerAccount );
DSDelete( pConfig->fServerPassword );
DSDelete( pConfig->fKerberosId );
DSDelete( pConfig->fMapSearchBase );
DSCFRelease( pConfig->fRecordAttrMapDict );
DSCFRelease( pConfig->fRecordTypeMapCFArray );
DSCFRelease( pConfig->fAttrTypeMapCFArray );
DSCFRelease( pConfig->fReplicaHostnames );
DSCFRelease( pConfig->fWriteableHostnames );
}
if( inServerMappingUpdate )
{
pConfig->bServerMappings = true;
}
else
{
cfBool = (CFBooleanRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLServerMappingsFlagKey ) );
if (cfBool != nil)
{
pConfig->bServerMappings = CFBooleanGetValue( cfBool );
}
}
cfBool = (CFBooleanRef) CFDictionaryGetValue( ldapDict, CFSTR( kXMLIsSSLFlagKey ) );
if (cfBool != nil)
{
pConfig->bIsSSL = CFBooleanGetValue( cfBool );
if (pConfig->bIsSSL)
{
pConfig->fServerPort = LDAPS_PORT; }
}
cfBool = (CFBooleanRef) CFDictionaryGetValue( ldapDict, CFSTR( kXMLLDAPv2ReadOnlyKey ) );
if (cfBool != nil)
{
pConfig->bLDAPv2ReadOnly = CFBooleanGetValue( cfBool );
}
cfNumber = (CFNumberRef) CFDictionaryGetValue( ldapDict, CFSTR( kXMLPortNumberKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &pConfig->fServerPort);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLOpenCloseTimeoutSecsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &pConfig->fOpenCloseTimeout);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLIdleTimeoutMinsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &pConfig->fIdleTimeout);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLDelayedRebindTrySecsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &pConfig->fDelayRebindTry);
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLSearchTimeoutSecsKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &pConfig->fSearchTimeout);
}
cfBool = (CFBooleanRef) CFDictionaryGetValue( ldapDict, CFSTR( kXMLUseDNSReplicasFlagKey ) );
if( cfBool != NULL )
{
pConfig->bDNSReplicas = CFBooleanGetValue( cfBool );
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLUserDefinedNameKey ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
DSDelete( pConfig->fUIName );
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
pConfig->fUIName = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, pConfig->fUIName, uiLength, kCFStringEncodingUTF8 );
}
if( inOverWriteAll )
{
cfBool= (CFBooleanRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLSecureUseFlagKey ) );
if (cfBool != nil)
{
pConfig->bSecureUse = CFBooleanGetValue( cfBool );
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLServerAccountKey ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
DSDelete( pConfig->fServerAccount );
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
pConfig->fServerAccount = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, pConfig->fServerAccount, uiLength, kCFStringEncodingUTF8 );
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLServerPasswordKey ) );
if ( cfStringRef != nil )
{
DSDelete( pConfig->fServerPassword );
if ( CFGetTypeID( cfStringRef ) == CFDataGetTypeID() )
{
cfDataRef = (CFDataRef) cfStringRef;
CFIndex passwordLen = CFDataGetLength(cfDataRef);
pConfig->fServerPassword = (char *) calloc( sizeof(char), passwordLen + 1 );
CFDataGetBytes( cfDataRef, CFRangeMake(0,passwordLen), (UInt8*)pConfig->fServerPassword );
}
else if ( CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
pConfig->fServerPassword = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, pConfig->fServerPassword, uiLength, kCFStringEncodingUTF8 );
}
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLKerberosId ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
DSDelete( pConfig->fKerberosId );
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
pConfig->fKerberosId = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, pConfig->fKerberosId, uiLength, kCFStringEncodingUTF8 );
}
if( cfBool = (CFBooleanRef)CFDictionaryGetValue( ldapDict, CFSTR(kXMLReferralFlagKey) ) )
{
if( CFGetTypeID( cfBool ) == CFBooleanGetTypeID() )
{
pConfig->bReferrals = CFBooleanGetValue( cfBool );
}
}
}
cfBool = (CFBooleanRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLMakeDefLDAPFlagKey ) );
if (cfBool != nil)
{
pConfig->bUseAsDefaultLDAP = CFBooleanGetValue( cfBool );
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( ldapDict, CFSTR( kXMLMapSearchBase ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
DSDelete( pConfig->fMapSearchBase );
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
pConfig->fMapSearchBase = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, pConfig->fMapSearchBase, uiLength, kCFStringEncodingUTF8 );
}
if( inServerMappingUpdate == false )
{
CFDictionaryRef cfLocalPolicy = (CFDictionaryRef) CFDictionaryGetValue( ldapDict, CFSTR(kXMLLocalSecurityKey) );
CFDictionaryRef cfConfigPolicy = (CFDictionaryRef) CFDictionaryGetValue( ldapDict, CFSTR(kXMLConfiguredSecurityKey) );
pConfig->fSecurityLevelLoc = CalculateSecurityPolicy( cfLocalPolicy );
pConfig->fSecurityLevel = pConfig->fSecurityLevelLoc | CalculateSecurityPolicy( cfConfigPolicy );
}
pConfig->bUpdated = true;
BuildLDAPMap( pConfig, ldapDict, pConfig->bServerMappings );
ConfigUnlock( pConfig );
}
DSDelete( server );
}
return( siResult );
}
sInt32 CLDAPv3Configs::MakeServerBasedMappingsLDAPConfig ( char *inServer, char *inMapSearchBase, int inOpenCloseTO, int inIdleTO, int inDelayRebindTry, int inSearchTO, int inPortNumber, bool inIsSSL, bool inMakeDefLDAP, bool inReferrals, bool inLDAPv2ReadOnly )
{
sInt32 siResult = eDSNoErr;
sLDAPConfigData *pConfig = nil;
if( inServer != NULL && strlen(inServer) )
{
pConfig = ConfigWithNodeNameLock( inServer );
if( pConfig == NULL )
{
pConfig = new sLDAPConfigData( inServer, inServer, inServer, inOpenCloseTO, inIdleTO, inDelayRebindTry, inSearchTO, inPortNumber, false, NULL, NULL, NULL, inMakeDefLDAP, true, inIsSSL, inMapSearchBase, kSecNoSecurity, kSecNoSecurity, inReferrals, inLDAPv2ReadOnly, false );
fConfigMapMutex.Wait();
fConfigMap[string(inServer)] = pConfig;
fConfigMapMutex.Signal();
}
else
{
pConfig->bUpdated = true;
ConfigUnlock( pConfig );
}
}
return( siResult );
}
sInt32 CLDAPv3Configs::BuildLDAPMap ( sLDAPConfigData *inConfig, CFDictionaryRef ldapDict, bool inServerMapppings )
{
CFArrayRef cfArrayRef = NULL;
cfArrayRef = (CFArrayRef) CFDictionaryGetValue( ldapDict, CFSTR( kXMLAttrTypeMapArrayKey ) );
if ( cfArrayRef != NULL && CFGetTypeID(cfArrayRef) == CFArrayGetTypeID() && CFArrayGetCount(cfArrayRef) > 0 )
{
DSCFRelease( inConfig->fAttrTypeMapCFArray );
inConfig->fAttrTypeMapCFArray = CFArrayCreateCopy(kCFAllocatorDefault, cfArrayRef);
}
cfArrayRef = (CFArrayRef) CFDictionaryGetValue(ldapDict, CFSTR(kXMLRecordTypeMapArrayKey));
CFDictionaryRef recordAttrMap = CreateNormalizedRecordAttrMap( cfArrayRef, inConfig->fAttrTypeMapCFArray );
if( recordAttrMap != NULL )
{
DSCFRelease( inConfig->fRecordTypeMapCFArray );
DSCFRelease( inConfig->fRecordAttrMapDict );
inConfig->fRecordTypeMapCFArray = CFArrayCreateCopy( kCFAllocatorDefault, cfArrayRef ); inConfig->fRecordAttrMapDict = recordAttrMap;
}
cfArrayRef = (CFArrayRef) CFDictionaryGetValue( ldapDict, CFSTR( kXMLReplicaHostnameListArrayKey ) );
if ( (cfArrayRef != nil) && (CFGetTypeID( cfArrayRef ) == CFArrayGetTypeID()) && (CFArrayGetCount(cfArrayRef) > 0) )
{
if (inConfig->fReplicaHostnames != nil)
{
CFRelease(inConfig->fReplicaHostnames);
inConfig->fReplicaHostnames = NULL;
}
inConfig->fReplicaHostnames = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, cfArrayRef);
}
cfArrayRef = (CFArrayRef) CFDictionaryGetValue( ldapDict, CFSTR( kXMLWriteableHostnameListArrayKey ) );
if ( (cfArrayRef != nil) && (CFGetTypeID( cfArrayRef ) == CFArrayGetTypeID()) && (CFArrayGetCount(cfArrayRef) > 0) )
{
if (inConfig->fWriteableHostnames != nil)
{
CFRelease(inConfig->fWriteableHostnames);
inConfig->fWriteableHostnames = NULL;
}
inConfig->fWriteableHostnames = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, cfArrayRef);
}
return( eDSNoErr );
}
CFDictionaryRef CLDAPv3Configs::CreateNormalizedAttributeMap( CFArrayRef inAttrMapArray, CFDictionaryRef inGlobalAttrMap )
{
CFMutableDictionaryRef newAttrMapDict = NULL;
CFIndex iTotal = 0;
CFIndex iGlobalMapTotal = 0;
if ( inGlobalAttrMap != NULL && (iGlobalMapTotal = CFDictionaryGetCount(inGlobalAttrMap)) > 0 )
{
newAttrMapDict = CFDictionaryCreateMutableCopy( kCFAllocatorDefault, 0, inGlobalAttrMap );
}
if ( inAttrMapArray != NULL && CFGetTypeID(inAttrMapArray) == CFArrayGetTypeID() && (iTotal = CFArrayGetCount(inAttrMapArray)) > 0 )
{
if ( newAttrMapDict == NULL )
{
newAttrMapDict = CFDictionaryCreateMutable( kCFAllocatorDefault, iTotal, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
}
for ( CFIndex iMapIndex = 0; iMapIndex < iTotal; iMapIndex++ )
{
CFDictionaryRef attrMapDict = (CFDictionaryRef) CFArrayGetValueAtIndex( inAttrMapArray, iMapIndex );
if ( attrMapDict != NULL && CFGetTypeID(attrMapDict) == CFDictionaryGetTypeID() )
{
CFStringRef cfStdName = (CFStringRef) CFDictionaryGetValue( attrMapDict, CFSTR( kXMLStdNameKey ) );
if ( cfStdName == NULL || CFGetTypeID( cfStdName ) != CFStringGetTypeID() )
continue;
CFArrayRef cfNativeArray = (CFArrayRef) CFDictionaryGetValue( attrMapDict, CFSTR( kXMLNativeMapArrayKey ) );
if ( cfNativeArray == NULL || CFGetTypeID(cfNativeArray) != CFArrayGetTypeID() )
continue;
CFIndex iNativeMapCount = CFArrayGetCount( cfNativeArray );
if( iNativeMapCount == 0 )
continue;
CFMutableArrayRef cfNewNativeMap = CFArrayCreateMutable( kCFAllocatorDefault, iNativeMapCount, &kCFTypeArrayCallBacks );
for( CFIndex iNativeIndex = 0; iNativeIndex < iNativeMapCount; iNativeIndex++ )
{
CFStringRef cfStringRef = (CFStringRef) CFArrayGetValueAtIndex( cfNativeArray, iNativeIndex );
if( cfStringRef != NULL && CFGetTypeID(cfStringRef) == CFStringGetTypeID() )
{
CFArrayAppendValue( cfNewNativeMap, cfStringRef );
}
}
if( CFArrayGetCount(cfNewNativeMap) != 0 )
{
CFDictionarySetValue( newAttrMapDict, cfStdName, cfNewNativeMap );
}
CFRelease( cfNewNativeMap );
cfNewNativeMap = NULL;
}
}
}
if( newAttrMapDict != NULL && CFDictionaryGetCount(newAttrMapDict) == 0 )
{
CFRelease( newAttrMapDict );
newAttrMapDict = NULL;
}
return newAttrMapDict;
}
CFDictionaryRef CLDAPv3Configs::CreateNormalizedRecordAttrMap( CFArrayRef inRecMapArray, CFArrayRef inGlobalAttrMapArray )
{
CFMutableDictionaryRef outRecMapDict = NULL;
CFIndex iTotal = 0;
if ( inRecMapArray != NULL && CFGetTypeID(inRecMapArray) == CFArrayGetTypeID() && (iTotal = CFArrayGetCount(inRecMapArray)) > 0 )
{
outRecMapDict = CFDictionaryCreateMutable( kCFAllocatorDefault, iTotal, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFDictionaryRef cfGlobalAttrMap = CreateNormalizedAttributeMap( inGlobalAttrMapArray, NULL );
for( CFIndex iMapIndex = 0; iMapIndex < iTotal; iMapIndex++ )
{
CFDictionaryRef recMapDict = (CFDictionaryRef) CFArrayGetValueAtIndex( inRecMapArray, iMapIndex );
if ( recMapDict != NULL )
{
CFStringRef cfStdName = (CFStringRef) CFDictionaryGetValue( recMapDict, CFSTR( kXMLStdNameKey ) );
if ( cfStdName == NULL || CFGetTypeID( cfStdName ) != CFStringGetTypeID() )
continue;
CFArrayRef cfNativeArray = (CFArrayRef) CFDictionaryGetValue( recMapDict, CFSTR( kXMLNativeMapArrayKey ) );
if ( cfNativeArray == NULL || CFGetTypeID(cfNativeArray) != CFArrayGetTypeID() )
continue;
CFIndex iNativeMapCount = CFArrayGetCount( cfNativeArray );
if( iNativeMapCount == 0 )
continue;
CFMutableArrayRef cfNewNativeArray = CFArrayCreateMutable( kCFAllocatorDefault, iNativeMapCount, &kCFTypeArrayCallBacks );
for( CFIndex iNativeIndex = 0; iNativeIndex < iNativeMapCount; iNativeIndex++ )
{
CFMutableDictionaryRef cfDictRef = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( cfNativeArray, iNativeIndex );
CFMutableDictionaryRef cfValidNativeDict = NULL;
if( CFGetTypeID(cfDictRef) == CFDictionaryGetTypeID() )
{
CFArrayRef cfObjectClasses = (CFArrayRef) CFDictionaryGetValue( cfDictRef, CFSTR(kXMLObjectClasses) );
if( cfObjectClasses != NULL && CFGetTypeID(cfObjectClasses) != CFArrayGetTypeID() )
continue;
CFStringRef cfSearchBase = (CFStringRef) CFDictionaryGetValue( cfDictRef, CFSTR(kXMLSearchBase) );
if( cfSearchBase != NULL && CFGetTypeID(cfSearchBase) != CFStringGetTypeID() )
cfSearchBase = NULL;
CFBooleanRef cfSearchScope = (CFBooleanRef) CFDictionaryGetValue( cfDictRef, CFSTR(kXMLOneLevelSearchScope) );
if( cfSearchScope != NULL && CFGetTypeID(cfSearchScope) != CFBooleanGetTypeID() )
cfSearchScope = NULL;
CFStringRef cfGroupClasses = (CFStringRef) CFDictionaryGetValue( cfDictRef, CFSTR(kXMLGroupObjectClasses) );
if( cfGroupClasses != NULL && CFGetTypeID(cfGroupClasses) != CFStringGetTypeID() )
cfGroupClasses = NULL;
CFIndex iObjClassCount = cfObjectClasses ? CFArrayGetCount( cfObjectClasses ) : 0;
for( CFIndex iObjClassIndex = 0; iObjClassIndex < iObjClassCount; iObjClassIndex++ )
{
if( CFGetTypeID(CFArrayGetValueAtIndex(cfObjectClasses, iObjClassIndex)) != CFStringGetTypeID() )
{
cfObjectClasses = NULL;
break;
}
}
if( cfObjectClasses != NULL )
{
cfValidNativeDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 4, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
if( cfSearchBase != NULL )
CFDictionarySetValue( cfValidNativeDict, CFSTR(kXMLSearchBase), cfSearchBase );
if( cfSearchScope != NULL )
CFDictionarySetValue( cfValidNativeDict, CFSTR(kXMLOneLevelSearchScope), cfSearchScope );
if( cfGroupClasses != NULL )
CFDictionarySetValue( cfValidNativeDict, CFSTR(kXMLGroupObjectClasses), cfGroupClasses );
CFDictionarySetValue( cfValidNativeDict, CFSTR(kXMLObjectClasses), cfObjectClasses );
}
}
else if ( CFGetTypeID(cfDictRef) == CFStringGetTypeID() )
{
CFArrayRef cfObjectClass = CFArrayCreate( kCFAllocatorDefault, (const void **)&cfDictRef, 1, &kCFTypeArrayCallBacks );
cfValidNativeDict = CFDictionaryCreateMutable( kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( cfValidNativeDict, CFSTR(kXMLObjectClasses), cfObjectClass );
CFRelease( cfObjectClass );
cfObjectClass = NULL;
}
if( cfValidNativeDict != NULL )
{
CFArrayAppendValue( cfNewNativeArray, cfValidNativeDict );
CFRelease( cfValidNativeDict );
cfValidNativeDict = NULL;
}
}
if( CFArrayGetCount( cfNewNativeArray ) > 0 )
{
CFMutableDictionaryRef cfNewMap = CFDictionaryCreateMutable( kCFAllocatorDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFArrayRef cfArray = (CFArrayRef) CFDictionaryGetValue( recMapDict, CFSTR(kXMLAttrTypeMapArrayKey) );
if( cfArray != NULL )
{
CFDictionaryRef cfAttribMap = CreateNormalizedAttributeMap( cfArray, cfGlobalAttrMap );
if( cfAttribMap != NULL )
{
CFDictionarySetValue( cfNewMap, CFSTR(kXMLAttrTypeMapDictKey), cfAttribMap );
CFRelease( cfAttribMap );
cfAttribMap = NULL;
}
}
else if( cfGlobalAttrMap )
{
CFDictionarySetValue( cfNewMap, CFSTR(kXMLAttrTypeMapDictKey), cfGlobalAttrMap );
}
CFDictionarySetValue( cfNewMap, CFSTR(kXMLNativeMapArrayKey), cfNewNativeArray );
CFDictionarySetValue( outRecMapDict, cfStdName, cfNewMap );
DSCFRelease( cfNewMap );
}
DSCFRelease( cfNewNativeArray );
}
}
DSCFRelease( cfGlobalAttrMap );
}
if( outRecMapDict != NULL && CFDictionaryGetCount(outRecMapDict) == 0 )
{
CFRelease( outRecMapDict );
outRecMapDict = NULL;
}
return outRecMapDict;
}
char *CLDAPv3Configs::GetVersion ( CFDictionaryRef configDict )
{
char *outVersion = nil;
CFStringRef cfStringRef = nil;
cfStringRef = (CFStringRef)CFDictionaryGetValue( configDict, CFSTR( kXMLLDAPVersionKey ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
outVersion = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, outVersion, uiLength, kCFStringEncodingUTF8 );
}
return( outVersion );
}
#pragma mark -
#pragma mark Server Mappings Utility Functions
CFDataRef CLDAPv3Configs::RetrieveServerMappings ( char *inServer, char *inMapSearchBase, int inPortNumber, bool inIsSSL, bool inReferrals, LDAP *inServerHost )
{
sInt32 siResult = eDSNoErr;
bool bResultFound = false;
int ldapMsgId = -1;
LDAPMessage *result = nil;
int ldapReturnCode = 0;
char *attrs[2] = {"description",NULL};
BerElement *ber;
struct berval **bValues;
char *pAttr = nil;
LDAP *serverHost = nil;
CFDataRef ourMappings = nil;
bool bCleanHost = false;
if (inServerHost == nil)
{
if ( (inServer != nil) && (inPortNumber != 0) )
{
serverHost = ldap_init( inServer, inPortNumber );
bCleanHost = true;
SetNetworkTimeoutsForHost( serverHost, kLDAPDefaultNetworkTimeoutInSeconds );
} }
else
{
serverHost = inServerHost;
}
if (serverHost != nil)
{
if (inIsSSL)
{
int ldapOptVal = LDAP_OPT_X_TLS_HARD;
ldap_set_option(serverHost, LDAP_OPT_X_TLS, &ldapOptVal);
}
ldap_set_option( serverHost, LDAP_OPT_REFERRALS, (inReferrals?LDAP_OPT_ON:LDAP_OPT_OFF) );
if (inMapSearchBase == nil)
{
ldapMsgId = ldap_search( serverHost, "", LDAP_SCOPE_SUBTREE, "(&(objectclass=organizationalUnit)(ou=macosxodconfig))", attrs, 0);
}
else
{
ldapMsgId = ldap_search( serverHost, inMapSearchBase, LDAP_SCOPE_SUBTREE, "(&(objectclass=organizationalUnit)(ou=macosxodconfig))", attrs, 0);
}
if ( ldapMsgId == -1 )
{
bResultFound = false;
}
else
{
bResultFound = true;
struct timeval tv;
tv.tv_sec = kLDAPDefaultOpenCloseTimeoutInSeconds;
tv.tv_usec = 0;
ldapReturnCode = ldap_result(serverHost, ldapMsgId, 0, &tv, &result);
}
if ( ( bResultFound ) && ( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) )
{
for ( pAttr = ldap_first_attribute (serverHost, result, &ber );
pAttr != NULL; pAttr = ldap_next_attribute(serverHost, result, ber ) )
{
if (( bValues = ldap_get_values_len (serverHost, result, pAttr )) != NULL)
{
if ( bValues[0] != NULL )
{
ourMappings = CFDataCreate(NULL,(UInt8 *)(bValues[0]->bv_val), bValues[0]->bv_len);
}
ldap_value_free_len(bValues);
}
if (pAttr != nil)
{
ldap_memfree( pAttr );
}
}
if (ber != nil)
{
ber_free( ber, 0 );
}
ldap_msgfree( result );
result = nil;
siResult = eDSNoErr;
}
else if (ldapReturnCode == LDAP_TIMEOUT)
{
siResult = eDSServerTimeout;
syslog(LOG_ALERT,"DSLDAPv3PlugIn: Retrieval of Server Mappings for [%s] LDAP server has timed out.", inServer);
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
else
{
siResult = eDSRecordNotFound;
syslog(LOG_ALERT,"DSLDAPv3PlugIn: Server Mappings for [%s] LDAP server not found.", inServer);
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
DSSearchCleanUp(serverHost, ldapMsgId);
if (bCleanHost)
{
ldap_unbind( serverHost );
}
}
return( ourMappings );
}
sInt32 CLDAPv3Configs::WriteServerMappings ( char* userName, char* password, CFDataRef inMappings )
{
sInt32 siResult = eDSNoErr;
LDAP *serverHost = nil;
CFPropertyListRef configPropertyList = nil;
CFDictionaryRef serverConfigDict = nil;
char *server = nil;
int portNumber = 389;
int openCloseTO = kLDAPDefaultOpenCloseTimeoutInSeconds;
CFStringRef cfStringRef = nil;
CFBooleanRef cfBool = nil;
CFNumberRef cfNumber = nil;
char *mapSearchBase = nil;
bool bIsSSL = false;
bool bLDAPv2ReadOnly = false;
int ldapReturnCode = 0;
int version = -1;
int bindMsgId = 0;
LDAPMessage *result = nil;
char *ldapDNString = nil;
uInt32 ldapDNLength = 0;
char *ourXMLBlob = nil;
char *ouvals[2];
char *mapvals[2];
char *ocvals[3];
LDAPMod oumod;
LDAPMod mapmod;
LDAPMod ocmod;
LDAPMod *mods[4];
try
{
if (inMappings != nil)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inMappings,
kCFPropertyListImmutable,
NULL);
if (configPropertyList != nil )
{
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
serverConfigDict = (CFDictionaryRef) configPropertyList;
}
if (serverConfigDict != nil)
{
cfStringRef = (CFStringRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLServerKey ) );
if ( cfStringRef != nil && 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 != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &openCloseTO);
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLIsSSLFlagKey ) );
if (cfBool != nil)
{
bIsSSL = CFBooleanGetValue( cfBool );
if (bIsSSL)
{
portNumber = LDAPS_PORT;
}
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLLDAPv2ReadOnlyKey ) );
if (cfBool != nil)
{
bLDAPv2ReadOnly = CFBooleanGetValue( cfBool );
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLPortNumberKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &portNumber);
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLMapSearchBase ) );
if ( cfStringRef != nil && 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 = nil;
}
if (bLDAPv2ReadOnly) throw( (sInt32)eDSReadOnly);
serverHost = ldap_init( server, portNumber );
if ( serverHost == nil ) throw( (sInt32)eDSCannotAccessSession );
if ( bIsSSL )
{
int ldapOptVal = LDAP_OPT_X_TLS_HARD;
ldap_set_option(serverHost, LDAP_OPT_X_TLS, &ldapOptVal);
}
SetNetworkTimeoutsForHost( serverHost, kLDAPDefaultNetworkTimeoutInSeconds );
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( serverHost );
serverHost = NULL;
throw( (sInt32)eDSCannotAccessSession );
}
else if ( ldap_result2error(serverHost, result, 1) != LDAP_SUCCESS )
{
throw( (sInt32)eDSCannotAccessSession );
}
if ( (serverHost != nil) && (mapSearchBase != nil) )
{
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] = "macosxodconfig";
ouvals[1] = NULL;
oumod.mod_op = 0;
oumod.mod_type = "ou";
oumod.mod_values = ouvals;
mapvals[0] = ourXMLBlob;
mapvals[1] = NULL;
mapmod.mod_op = 0;
mapmod.mod_type = "description";
mapmod.mod_values = mapvals;
ocvals[0] = "top";
ocvals[1] = "organizationalUnit";
ocvals[2] = NULL;
ocmod.mod_op = 0;
ocmod.mod_type = "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;
}
} } }
} catch ( sInt32 err )
{
siResult = err;
if (configPropertyList != nil)
{
CFRelease(configPropertyList); configPropertyList = nil;
}
}
if ( serverHost != nil )
{
ldap_unbind( serverHost );
serverHost = nil;
}
if ( mapSearchBase != nil )
{
free( mapSearchBase );
mapSearchBase = nil;
}
if ( ourXMLBlob != nil )
{
free( ourXMLBlob );
ourXMLBlob = nil;
}
if ( ldapDNString != nil )
{
free( ldapDNString );
ldapDNString = nil;
}
return( siResult );
}
CFDataRef CLDAPv3Configs::ReadServerMappings ( LDAP *serverHost, CFDataRef inMappings )
{
sInt32 siResult = eDSNoErr;
CFPropertyListRef configPropertyList = nil;
CFMutableDictionaryRef serverConfigDict = nil;
char *configVersion = nil;
CFStringRef cfStringRef = nil;
CFBooleanRef cfBool = false;
char *mapSearchBase = nil;
bool bIsSSL = false;
bool bServerMappings = false;
bool bUseConfig = false;
bool bReferrals = true;
CFNumberRef cfNumber = 0;
char *server = nil;
int portNumber = 389;
CFDataRef outMappings = nil;
try
{
if (inMappings != nil)
{
configPropertyList = CFPropertyListCreateFromXMLData( kCFAllocatorDefault,
inMappings,
kCFPropertyListMutableContainers,
NULL);
if (configPropertyList != nil )
{
if ( CFDictionaryGetTypeID() == CFGetTypeID( configPropertyList ) )
{
serverConfigDict = (CFMutableDictionaryRef) configPropertyList; }
if (serverConfigDict != nil)
{
configVersion = GetVersion(serverConfigDict);
if ( configVersion == nil ) throw( (sInt32)eDSVersionMismatch ); if (configVersion != nil)
{
if (strcmp(configVersion,"DSLDAPv3PlugIn Version 1.5") == 0)
{
cfBool = (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLEnableUseFlagKey ) );
if (cfBool != nil)
{
bUseConfig = CFBooleanGetValue( cfBool );
}
if ( bUseConfig )
{
cfBool = (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLServerMappingsFlagKey ) );
if (cfBool != nil)
{
bServerMappings = CFBooleanGetValue( cfBool );
}
if (bServerMappings)
{
cfStringRef = (CFStringRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLServerKey ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
server = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, server, uiLength, kCFStringEncodingUTF8 );
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLIsSSLFlagKey ) );
if (cfBool != nil)
{
bIsSSL = CFBooleanGetValue( cfBool );
if (bIsSSL)
{
portNumber = LDAPS_PORT; }
}
cfBool= (CFBooleanRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLReferralFlagKey ) );
if (cfBool != nil)
{
bReferrals = CFBooleanGetValue( cfBool );
}
cfNumber = (CFNumberRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLPortNumberKey ) );
if ( cfNumber != nil )
{
CFNumberGetValue(cfNumber, kCFNumberIntType, &portNumber);
}
cfStringRef = (CFStringRef)CFDictionaryGetValue( serverConfigDict, CFSTR( kXMLMapSearchBase ) );
if ( cfStringRef != nil && CFGetTypeID( cfStringRef ) == CFStringGetTypeID() )
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(cfStringRef), kCFStringEncodingUTF8 ) + 1;
mapSearchBase = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( cfStringRef, mapSearchBase, uiLength, kCFStringEncodingUTF8 );
}
}
} }
free( configVersion );
configVersion = nil;
}
}
CFRelease(configPropertyList); configPropertyList = nil;
}
outMappings = RetrieveServerMappings( server, mapSearchBase, portNumber, bIsSSL, bReferrals );
}
} catch ( sInt32 err )
{
siResult = err;
if (configPropertyList != nil)
{
CFRelease(configPropertyList); configPropertyList = nil;
}
}
if ( server != nil )
{
free( server );
server = nil;
}
if ( mapSearchBase != nil )
{
free( mapSearchBase );
mapSearchBase = nil;
}
return( outMappings );
}
#pragma mark -
#pragma mark Extracting Maps from Configurations
char* CLDAPv3Configs::ExtractRecMap( const char *inRecType, CFDictionaryRef inRecordTypeMapCFDict, int inIndex, bool *outOCGroup, CFArrayRef *outOCListCFArray, ber_int_t* outScope )
{
char *outResult = NULL;
if ( (inRecordTypeMapCFDict != NULL) && (inRecType != NULL) )
{
CFStringRef cfRecTypeRef = CFStringCreateWithCString( kCFAllocatorDefault, inRecType, kCFStringEncodingUTF8 );
CFDictionaryRef cfRecordMap = (CFDictionaryRef) CFDictionaryGetValue( inRecordTypeMapCFDict, cfRecTypeRef );
if ( cfRecordMap != NULL )
{
CFArrayRef cfNativeArray = (CFArrayRef) CFDictionaryGetValue( cfRecordMap, CFSTR(kXMLNativeMapArrayKey) );
if ( inIndex <= CFArrayGetCount(cfNativeArray) )
{
CFDictionaryRef cfCurrentMap = (CFDictionaryRef) CFArrayGetValueAtIndex( cfNativeArray, inIndex-1 );
CFStringRef searchBase = (CFStringRef) CFDictionaryGetValue( cfCurrentMap, CFSTR(kXMLSearchBase) );
if (searchBase != NULL)
{
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(searchBase), kCFStringEncodingUTF8 ) + 1;
outResult = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( searchBase, outResult, uiLength, kCFStringEncodingUTF8 );
}
if( outOCListCFArray != NULL && outOCGroup != NULL )
{
*outOCGroup = 0;
CFArrayRef objectClasses = (CFArrayRef)CFDictionaryGetValue( cfCurrentMap, CFSTR( kXMLObjectClasses ) );
if ( objectClasses != NULL )
{
CFStringRef groupOCString = (CFStringRef)CFDictionaryGetValue( cfCurrentMap, CFSTR( kXMLGroupObjectClasses ) );
if ( groupOCString != NULL && CFStringCompare( groupOCString, CFSTR("AND"), 0 ) == kCFCompareEqualTo )
{
*outOCGroup = 1;
}
*outOCListCFArray = CFArrayCreateCopy(kCFAllocatorDefault, objectClasses);
} }
if (outScope != NULL)
{
CFBooleanRef cfBoolRef = (CFBooleanRef)CFDictionaryGetValue( cfCurrentMap, CFSTR( kXMLOneLevelSearchScope ) );
if (cfBoolRef != NULL && CFBooleanGetValue(cfBoolRef))
{
*outScope = LDAP_SCOPE_ONELEVEL;
}
else
{
*outScope = LDAP_SCOPE_SUBTREE;
}
} } }
DSCFRelease(cfRecTypeRef);
}
return( outResult );
}
char* CLDAPv3Configs::ExtractAttrMap( const char *inRecType, const char *inAttrType, CFDictionaryRef inRecordTypeMapCFDict, int inIndex )
{
char *outResult = NULL;
if ( (inRecordTypeMapCFDict != NULL) && (inRecType != NULL) && (inAttrType != NULL) && (inIndex >= 1) )
{
CFStringRef cfRecTypeRef = CFStringCreateWithCString(kCFAllocatorDefault, inRecType, kCFStringEncodingUTF8);
CFDictionaryRef cfRecordMap = (CFDictionaryRef) CFDictionaryGetValue( inRecordTypeMapCFDict, cfRecTypeRef );
if( cfRecordMap != NULL )
{
CFDictionaryRef cfAttrMapDictRef = (CFDictionaryRef) CFDictionaryGetValue( cfRecordMap, CFSTR(kXMLAttrTypeMapDictKey) );
if( cfAttrMapDictRef != NULL )
{
CFStringRef cfAttrTypeRef = CFStringCreateWithCString( kCFAllocatorDefault, inAttrType, kCFStringEncodingUTF8 );
CFArrayRef cfMapArray = (CFArrayRef) CFDictionaryGetValue( cfAttrMapDictRef, cfAttrTypeRef );
if( cfMapArray != NULL && inIndex <= CFArrayGetCount(cfMapArray))
{
CFStringRef nativeMapString = (CFStringRef) CFArrayGetValueAtIndex( cfMapArray, inIndex-1 );
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(nativeMapString), kCFStringEncodingUTF8 ) + 1;
outResult = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( nativeMapString, outResult, uiLength, kCFStringEncodingUTF8 );
}
DSCFRelease(cfAttrTypeRef);
}
}
DSCFRelease(cfRecTypeRef);
}
return( outResult );
}
char* CLDAPv3Configs::ExtractStdAttrName( char *inRecType, CFDictionaryRef inRecordTypeMapCFDict, int &inputIndex )
{
char *outResult = NULL;
if ( (inRecordTypeMapCFDict != NULL) && (inRecType != NULL) && (inputIndex >= 1) )
{
CFStringRef cfRecTypeRef = CFStringCreateWithCString(kCFAllocatorDefault, inRecType, kCFStringEncodingUTF8);
CFDictionaryRef cfRecordMap = (CFDictionaryRef) CFDictionaryGetValue( inRecordTypeMapCFDict, cfRecTypeRef );
if( cfRecordMap != NULL )
{
CFDictionaryRef cfAttrMapDict = (CFDictionaryRef) CFDictionaryGetValue( cfRecordMap, CFSTR( kXMLAttrTypeMapDictKey ) );
if (cfAttrMapDict != NULL)
{
CFIndex iTotalEntries = CFDictionaryGetCount( cfAttrMapDict );
if( inputIndex <= iTotalEntries )
{
CFStringRef *keys = (CFStringRef *) calloc( iTotalEntries, sizeof(CFStringRef) );
CFDictionaryGetKeysAndValues( cfAttrMapDict, (const void **)keys, NULL );
uInt32 uiLength = (uInt32) CFStringGetMaximumSizeForEncoding( CFStringGetLength(keys[inputIndex - 1]), kCFStringEncodingUTF8 ) + 1;
outResult = (char *) calloc( sizeof(char), uiLength );
CFStringGetCString( keys[inputIndex - 1], outResult, uiLength, kCFStringEncodingUTF8 );
DSFree( keys );
}
}
}
CFRelease(cfRecTypeRef);
}
return( outResult );
}
int CLDAPv3Configs::AttrMapsCount( const char *inRecType, const char *inAttrType, CFDictionaryRef inRecordTypeMapCFDict )
{
int outCount = 0;
if ( (inRecordTypeMapCFDict != NULL) && (inRecType != NULL) && (inAttrType != NULL) )
{
CFStringRef cfRecTypeRef = CFStringCreateWithCString(kCFAllocatorDefault, inRecType, kCFStringEncodingUTF8);
CFDictionaryRef cfRecordMap = (CFDictionaryRef) CFDictionaryGetValue( inRecordTypeMapCFDict, cfRecTypeRef );
if( cfRecordMap != NULL )
{
CFDictionaryRef cfAttrMapDictRef = (CFDictionaryRef) CFDictionaryGetValue( cfRecordMap, CFSTR(kXMLAttrTypeMapDictKey) );
if( cfAttrMapDictRef != NULL )
{
CFStringRef cfAttrTypeRef = CFStringCreateWithCString(kCFAllocatorDefault, inAttrType, kCFStringEncodingUTF8);
CFArrayRef cfMapArray = (CFArrayRef) CFDictionaryGetValue( cfAttrMapDictRef, cfAttrTypeRef );
if( cfMapArray != NULL )
{
outCount = CFArrayGetCount( cfMapArray );
}
CFRelease(cfAttrTypeRef);
}
}
CFRelease(cfRecTypeRef);
}
return( outCount );
}
#pragma mark -
#pragma mark Utility Function
bool CLDAPv3Configs::CreatePrefDirectory( void )
{
char *filenameString = "/Library/Preferences/DirectoryService/DSLDAPv3PlugInConfig.plist";
int siResult = eDSNoErr;
struct stat statResult;
DBGLOG( kLogPlugin, "CLDAPv3Configs: Checking for LDAP XML config file:" );
DBGLOG1( kLogPlugin, "CLDAPv3Configs: %s", filenameString );
siResult = ::stat( filenameString, &statResult );
if (siResult != eDSNoErr)
{
char *tempPath = "/Library/Preferences";
siResult = ::stat( tempPath, &statResult );
if (siResult != eDSNoErr)
{
::mkdir( tempPath, 0775 );
::chmod( tempPath, 0775 ); }
tempPath = "/Library/Preferences/DirectoryService";
siResult = ::stat( tempPath, &statResult );
if (siResult != eDSNoErr)
{
::mkdir( tempPath, 0775 );
::chmod( tempPath, 0775 ); }
}
return (siResult == eDSNoErr);
}
bool CLDAPv3Configs::ConvertLDAPv2Config( void )
{
struct stat statResult;
const char *prefPath = "/Library/Preferences/DirectoryService/DSLDAPPlugInConfig.clpi";
bool bReturn = false;
CFDataRef sV2ConfigData = NULL;
CFMutableDictionaryRef sV2Config = NULL;
CFMutableDictionaryRef sV3Config = NULL;
if( stat("/System/Library/Frameworks/DirectoryService.framework/Resources/Plugins/LDAPv2.dsplug", &statResult) != 0 )
{
char newName[PATH_MAX] = { 0 };
CFStringRef sPath = ::CFStringCreateWithCString( kCFAllocatorDefault, prefPath, kCFStringEncodingUTF8 );
strcpy( newName, prefPath );
strcat( newName, ".v3converted" );
if( ::stat( prefPath, &statResult ) == 0 ) {
CFURLRef sConfigFileURL = ::CFURLCreateWithFileSystemPath( kCFAllocatorDefault, sPath, kCFURLPOSIXPathStyle, false );
CFURLCreateDataAndPropertiesFromResource( kCFAllocatorDefault, sConfigFileURL, &sV2ConfigData, NULL, NULL, NULL );
CFRelease( sConfigFileURL );
sConfigFileURL = NULL;
if( sV2ConfigData )
{
sV2Config = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, sV2ConfigData, kCFPropertyListMutableContainers, NULL );
CFRelease( sV2ConfigData );
sV2ConfigData = NULL;
}
XMLConfigLock();
if (fXMLData != NULL)
{
sV3Config = (CFMutableDictionaryRef) CFPropertyListCreateFromXMLData( kCFAllocatorDefault, fXMLData, kCFPropertyListMutableContainers, NULL );
}
XMLConfigUnlock();
if( sV2Config && sV3Config )
{
CFStringRef tConfigKey = CFSTR( kXMLConfigArrayKey );
CFMutableArrayRef tV3ConfigEntries = (CFMutableArrayRef) CFDictionaryGetValue( sV3Config, tConfigKey );
CFArrayRef tV2ConfigEntries = (CFArrayRef) CFDictionaryGetValue( sV2Config, tConfigKey );
CFMutableDictionaryRef tV2ConfigEntry = NULL;
if( tV2ConfigEntries )
{
CFIndex v2ConfigCount = CFArrayGetCount(tV2ConfigEntries);
CFIndex v2ConfigIndex;
for( v2ConfigIndex = 0; v2ConfigIndex < v2ConfigCount; v2ConfigIndex++ )
{
tV2ConfigEntry = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( tV2ConfigEntries, v2ConfigIndex );
if( tV2ConfigEntry )
{
CFTypeRef tObjectValue = CFDictionaryGetValue( tV2ConfigEntry, CFSTR(kXMLServerKey) );
if( tObjectValue )
{
if( tV3ConfigEntries )
{
CFIndex count = CFArrayGetCount( tV3ConfigEntries );
CFIndex index;
for( index = 0; index < count; index++ )
{
CFDictionaryRef tServerConfig = (CFDictionaryRef) CFArrayGetValueAtIndex( tV3ConfigEntries, index );
CFStringRef tServer = (CFStringRef) CFDictionaryGetValue( tServerConfig, CFSTR(kXMLServerKey) );
if( tServer && CFStringCompare(tServer, (CFStringRef) tObjectValue, kCFCompareCaseInsensitive) == kCFCompareEqualTo )
{
CFDictionarySetValue( tV2ConfigEntry, CFSTR(kXMLEnableUseFlagKey), kCFBooleanFalse );
}
}
}
}
CFDictionarySetValue( tV2ConfigEntry, CFSTR(kXMLServerMappingsFlagKey), kCFBooleanFalse );
CFDictionarySetValue( tV2ConfigEntry, CFSTR(kXMLMakeDefLDAPFlagKey), kCFBooleanFalse );
CFStringRef tKeyValue = CFSTR( kXMLUserDefinedNameKey );
tObjectValue = CFDictionaryGetValue( tV2ConfigEntry, tKeyValue );
if( tObjectValue )
{
CFStringRef sNewName = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("%@ (from LDAPv2)"), tObjectValue );
CFDictionarySetValue( tV2ConfigEntry, tKeyValue, sNewName );
CFRelease( sNewName );
}
CFArrayRef tRecMap = (CFArrayRef) CFDictionaryGetValue( tV2ConfigEntry, CFSTR(kXMLRecordTypeMapArrayKey) );
if( tRecMap )
{
CFIndex index;
CFIndex count = CFArrayGetCount( tRecMap );
for( index = 0; index < count; index++ )
{
CFMutableDictionaryRef tRecordMapDict = (CFMutableDictionaryRef) CFArrayGetValueAtIndex( tRecMap, index );
CFMutableArrayRef tNativeArray = (CFMutableArrayRef) CFDictionaryGetValue( tRecordMapDict, CFSTR(kXMLNativeMapArrayKey) );
CFArrayRef sBlankArray = CFArrayCreate( NULL, NULL, 0, &kCFTypeArrayCallBacks );
CFDictionarySetValue( tRecordMapDict, CFSTR(kXMLAttrTypeMapArrayKey), sBlankArray );
CFRelease( sBlankArray );
if( tNativeArray == NULL )
{
tNativeArray = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
CFDictionarySetValue( tRecordMapDict, CFSTR(kXMLNativeMapArrayKey), tNativeArray );
CFRelease( tNativeArray );
}
CFMutableDictionaryRef sNewNativeDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
CFDictionarySetValue( sNewNativeDict, CFSTR(kXMLGroupObjectClasses), CFSTR("OR") );
if( CFArrayGetCount( tNativeArray ) > 0 )
{
CFDictionarySetValue( sNewNativeDict, CFSTR(kXMLSearchBase), CFArrayGetValueAtIndex(tNativeArray, 0) );
}
CFArrayRemoveAllValues( tNativeArray );
CFArrayAppendValue( tNativeArray, sNewNativeDict );
CFRelease( sNewNativeDict );
}
}
if( tV3ConfigEntries == NULL )
{
tV3ConfigEntries = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFDictionarySetValue( sV3Config, tConfigKey, tV3ConfigEntries );
CFRelease( tV3ConfigEntries );
}
CFArrayAppendValue( tV3ConfigEntries, tV2ConfigEntry );
CFDataRef aXMLData = (CFDataRef) CFPropertyListCreateXMLData( kCFAllocatorDefault, sV3Config );
SetXMLConfig(aXMLData);
CFRelease(aXMLData);
aXMLData = 0;
bReturn = true;
}
}
}
}
rename( prefPath, newName );
}
CFRelease( sPath );
sPath = NULL;
}
if( sV2Config )
{
CFRelease( sV2Config );
sV2Config = NULL;
}
if( sV3Config )
{
CFRelease( sV3Config );
sV3Config = NULL;
}
return bReturn;
}