#include <stdio.h>
#include <string.h> //used for strcpy, etc.
#include <stdlib.h> //used for malloc
#include <ctype.h> //use for isprint
#include <syslog.h> //error logging
#include <arpa/inet.h> // inet_ntop
#include <netinet/in.h> // struct sockaddr_in
#include <ifaddrs.h>
#include <fcntl.h>
#include <sasl.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include "CLDAPNode.h"
#include "CLDAPv3Plugin.h"
#include "CLog.h"
#include "DSLDAPUtils.h"
#define OCSEPCHARS " '()$"
extern CPlugInRef *gLDAPConfigTable; extern uInt32 gLDAPConfigTableLen;
extern bool gServerOS;
typedef struct saslDefaults
{
char *authcid;
char *password;
} saslDefaults;
bool CLDAPNode::fCheckThreadActive = false;
class CLDAPv3Plugin;
bool checkReachability(struct sockaddr *destAddr);
bool checkReachability(struct sockaddr *destAddr)
{
SCNetworkReachabilityRef target = NULL;
SCNetworkConnectionFlags flags;
bool ok = false;
target = SCNetworkReachabilityCreateWithAddress(NULL, destAddr);
if (target == NULL) {
DBGLOG( kLogPlugin, "CLDAPNode::checkReachability: Can't determine reachability." );
goto done;
}
if (!SCNetworkReachabilityGetFlags(target, &flags)) {
DBGLOG( kLogPlugin, "CLDAPNode::checkReachability: Can't retrieve reachability flags.");
goto done;
}
if (!(flags & kSCNetworkFlagsReachable)) {
DBGLOG( kLogPlugin, "CLDAPNode::checkReachability: Not reachable [not kSCNetworkFlagsReachable]." );
goto done;
}
if (flags & kSCNetworkFlagsConnectionRequired) {
DBGLOG( kLogPlugin, "CLDAPNode::checkReachability: Not reachable [kSCNetworkFlagsConnectionRequired]." );
goto done;
}
ok = true;
done :
if (target) CFRelease(target);
return(ok);
}
int sasl_interact( LDAP *ld, unsigned flags, void *inDefaults, void *inInteract );
int sasl_interact( LDAP *ld, unsigned flags, void *inDefaults, void *inInteract )
{
sasl_interact_t *interact = (sasl_interact_t *)inInteract;
saslDefaults *defaults = (saslDefaults *) inDefaults;
if( ld == NULL ) return LDAP_PARAM_ERROR;
while( interact->id != SASL_CB_LIST_END )
{
const char *dflt = interact->defresult;
switch( interact->id )
{
case SASL_CB_AUTHNAME:
if( defaults ) dflt = defaults->authcid;
break;
case SASL_CB_PASS:
if( defaults ) dflt = defaults->password;
break;
}
if( (dflt && *dflt) || interact->id == SASL_CB_USER )
{
interact->result = (dflt && *dflt) ? dflt : "";
interact->len = strlen( (char *)interact->result );
} else {
return LDAP_OTHER;
}
interact++;
}
return LDAP_SUCCESS;
}
int doSASLBindAttemptIfPossible( LDAP *inLDAPHost, sLDAPConfigData *pConfig, char *ldapAcct, char *ldapPasswd );
int doSASLBindAttemptIfPossible( LDAP *inLDAPHost, sLDAPConfigData *pConfig, char *ldapAcct, char *ldapPasswd )
{
int siResult = LDAP_OTHER;
if( pConfig != NULL && pConfig->fSASLmethods != NULL && CFArrayGetCount(pConfig->fSASLmethods) && ldapAcct && strlen(ldapAcct) && ldapPasswd && strlen(ldapPasswd) )
{
CFRange range = CFRangeMake( 0, CFArrayGetCount(pConfig->fSASLmethods) );
struct saslDefaults defaults;
char *tempString = strdup( ldapAcct );
char *workString = strchr( tempString, '=' );
if( workString != NULL ) {
workString++;
defaults.authcid = strsep( &workString, "," );
} else {
defaults.authcid = tempString;
}
defaults.password = ldapPasswd;
if( CFArrayContainsValue(pConfig->fSASLmethods, range, CFSTR("CRAM-MD5")) )
{
DBGLOG( kLogPlugin, "CLDAPNode::Attempting CRAM-MD5 Authentication" );
siResult = ldap_sasl_interactive_bind_s( inLDAPHost, NULL, "CRAM-MD5", NULL, NULL, LDAP_SASL_QUIET, sasl_interact, &defaults );
} else {
DBGLOG( kLogPlugin, "CLDAPNode::No SASL methods found for server." );
}
free( tempString );
} else {
DBGLOG( kLogPlugin, "CLDAPNode::Skipping SASL methods for server." );
}
return siResult;
}
void *checkFailedServers( void *data );
void *checkFailedServers( void *data )
{
CLDAPNode *ldapNode = (CLDAPNode *)data;
ldapNode->CheckFailed();
CLDAPNode::fCheckThreadActive = false;
return NULL;
}
void LogFailedConnection(const char *inTag, const char *inServerName, int inDisabledIntervalDuration);
void LogFailedConnection(const char *inTag, const char *inServerName, int inDisabledIntervalDuration)
{
if ((inTag != nil) && (inServerName != nil))
{
syslog(LOG_INFO,"%s: Timed out in attempt to bind to [%s] LDAP server.", inTag, inServerName);
syslog(LOG_INFO,"%s: Disabled future attempts to bind to [%s] LDAP server for next %d seconds.", inTag, inServerName, inDisabledIntervalDuration);
DBGLOG1( kLogPlugin, "CLDAPNode::Disabled future attempts to bind to LDAP server %s", inServerName );
}
else
{
syslog(LOG_INFO,"%s: Logging Failed LDAP connection with incomplete data", (inTag ? inTag : "unknown"));
DBGLOG( kLogPlugin, "CLDAPNode::Failed LDAP connection" );
}
}
void SetSockList(int *inSockList, int inSockCount, bool inClose);
void SetSockList(int *inSockList, int inSockCount, bool inClose)
{
for (int iCount = 0; iCount < inSockCount; iCount++)
{
if ( (inClose) && (inSockList[iCount] >= 0) )
{
close(inSockList[iCount]);
}
inSockList[iCount] = -1;
}
}
CLDAPNode::CLDAPNode ( void )
{
}
CLDAPNode::~CLDAPNode ( void )
{
}
sInt32 CLDAPNode::SafeOpen ( char *inNodeName,
LDAP **outLDAPHost,
uInt32 *outLDAPConfigTableIndex,
CLDAPv3Configs *inConfigFromXML )
{
sInt32 siResult = eDSNoErr;
sLDAPNodeStruct *pLDAPNodeStruct = nil;
uInt32 iTableIndex = 0;
sLDAPConfigData *pConfig = nil;
int ldapPort = LDAP_PORT;
char *aLDAPName = nil;
bool bConfigFound = false;
LDAPNodeMapI aLDAPNodeMapI;
string aNodeName(inNodeName);
uInt32 openTO = kLDAPDefaultOpenCloseTimeoutInSeconds;
fLDAPNodeOpenMutex.Wait();
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI == fLDAPNodeMap.end())
{
pLDAPNodeStruct = (sLDAPNodeStruct *) calloc(1, sizeof(sLDAPNodeStruct));
pLDAPNodeStruct->fRefCount = 1;
pLDAPNodeStruct->fLDAPSessionMutex = new DSMutexSemaphore();
for (iTableIndex=1; iTableIndex<gLDAPConfigTableLen; iTableIndex++)
{
pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( iTableIndex );
if (pConfig != nil)
{
openTO = pConfig->fOpenCloseTimeout;
if (pConfig->fServerName != nil)
{
if (::strcmp(pConfig->fServerName,inNodeName) == 0)
{
ldapPort = pConfig->fServerPort;
bConfigFound = true;
pLDAPNodeStruct->fLDAPConfigTableIndex = iTableIndex;
pLDAPNodeStruct->fIdleTO = 2 * pConfig->fIdleTimeout;
pLDAPNodeStruct->fDelayRebindTry = pConfig->fDelayRebindTry;
break;
} } } }
if (!bConfigFound)
{
siResult = ParseLDAPNodeName( inNodeName, &aLDAPName, &ldapPort );
if (siResult == eDSNoErr)
{
pLDAPNodeStruct->fServerName = aLDAPName;
pLDAPNodeStruct->fDirectLDAPPort = ldapPort;
pLDAPNodeStruct->fLDAPConfigTableIndex = 0;
}
}
fLDAPNodeMap[aNodeName] = pLDAPNodeStruct;
fLDAPNodeOpenMutex.Signal();
}
else
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
pLDAPNodeStruct->fRefCount++;
if (( pLDAPNodeStruct->fLDAPConfigTableIndex < gLDAPConfigTableLen) && ( pLDAPNodeStruct->fLDAPConfigTableIndex >= 1 ))
{
pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( pLDAPNodeStruct->fLDAPConfigTableIndex );
if (pConfig != nil)
{
openTO = pConfig->fOpenCloseTimeout;
if (pConfig->bGetServerMappings) {
bConfigFound = true;
}
}
}
fLDAPNodeOpenMutex.Signal();
}
if (siResult == eDSNoErr)
{
if (pLDAPNodeStruct->fConnectionStatus == kConnectionUnknown)
{
EnsureCheckFailedConnectionsThreadIsRunning();
struct mach_timebase_info timeBaseInfo;
uint64_t delay;
mach_timebase_info( &timeBaseInfo );
delay = (((uint64_t)(NSEC_PER_SEC * openTO) * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer);
mach_wait_until( mach_absolute_time() + delay );
}
if (pLDAPNodeStruct->fConnectionStatus != kConnectionSafe)
{
siResult = eDSCannotAccessSession;
}
if (siResult == eDSNoErr)
{
if (pLDAPNodeStruct->fLDAPSessionMutex != nil)
{
pLDAPNodeStruct->fLDAPSessionMutex->Wait();
}
CheckSASLMethods( pLDAPNodeStruct, inConfigFromXML );
siResult = BindProc( pLDAPNodeStruct, inConfigFromXML );
if( bConfigFound && pConfig->bGetServerMappings && pLDAPNodeStruct->fHost )
{
RetrieveServerMappingsIfRequired(pLDAPNodeStruct, inConfigFromXML);
ldap_unbind_ext( pLDAPNodeStruct->fHost, NULL, NULL );
pLDAPNodeStruct->fHost = nil;
siResult = BindProc( pLDAPNodeStruct, inConfigFromXML );
}
if( siResult != eDSNoErr ) {
pLDAPNodeStruct->fRefCount--;
}
*outLDAPHost = pLDAPNodeStruct->fHost;
*outLDAPConfigTableIndex = pLDAPNodeStruct->fLDAPConfigTableIndex;
if (pLDAPNodeStruct->fLDAPSessionMutex != nil)
{
pLDAPNodeStruct->fLDAPSessionMutex->Signal();
}
}
}
return(siResult);
}
sInt32 CLDAPNode::AuthOpen ( char *inNodeName,
LDAP *inHost,
char *inUserName,
void *inAuthCredential,
char *inAuthType,
LDAP **outLDAPHost,
uInt32 *inOutLDAPConfigTableIndex,
bool shouldCloseOld )
{
sInt32 siResult = eDSNoErr;
sLDAPNodeStruct *pLDAPNodeStruct = nil;
sLDAPNodeStruct *pLDAPAuthNodeStruct = nil;
int ldapPort = LDAP_PORT;
char *aLDAPName = nil;
LDAPNodeMapI aLDAPNodeMapI;
string aNodeName(inNodeName);
fLDAPNodeOpenMutex.Wait();
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
pLDAPAuthNodeStruct = (sLDAPNodeStruct *) calloc(1, sizeof(sLDAPNodeStruct));
if (pLDAPNodeStruct->fLDAPConfigTableIndex != 0)
{
pLDAPAuthNodeStruct->fLDAPConfigTableIndex = pLDAPNodeStruct->fLDAPConfigTableIndex;
}
else
{
pLDAPAuthNodeStruct->fServerName = pLDAPNodeStruct->fServerName;
pLDAPAuthNodeStruct->fDirectLDAPPort = pLDAPNodeStruct->fDirectLDAPPort;
}
pLDAPAuthNodeStruct->fUserName = inUserName;
pLDAPAuthNodeStruct->fAuthCredential = inAuthCredential;
pLDAPAuthNodeStruct->fAuthType = inAuthType;
fLDAPNodeOpenMutex.Signal();
siResult = BindProc( pLDAPAuthNodeStruct, nil, shouldCloseOld );
if (siResult == eDSNoErr)
{
*outLDAPHost = pLDAPAuthNodeStruct->fHost;
*inOutLDAPConfigTableIndex = pLDAPNodeStruct->fLDAPConfigTableIndex;
if ( shouldCloseOld )
{
fLDAPNodeOpenMutex.Wait();
if (inHost == pLDAPNodeStruct->fHost)
{
pLDAPNodeStruct->fRefCount--;
if (pLDAPNodeStruct->fRefCount == 0 && pLDAPNodeStruct->fConnectionStatus == kConnectionSafe)
{
CleanLDAPNodeStruct(pLDAPNodeStruct);
fLDAPNodeMap.erase(aNodeName);
}
}
else if (inHost != nil)
{
ldap_unbind(inHost);
}
inHost = nil;
fLDAPNodeOpenMutex.Signal();
}
}
if (pLDAPAuthNodeStruct != nil)
{
free(pLDAPAuthNodeStruct);
pLDAPAuthNodeStruct = nil;
}
}
else if (inHost != nil)
{
fLDAPNodeOpenMutex.Signal();
pLDAPAuthNodeStruct = (sLDAPNodeStruct *) calloc(1, sizeof(sLDAPNodeStruct));
siResult = ParseLDAPNodeName( inNodeName, &aLDAPName, &ldapPort );
if (siResult == eDSNoErr)
{
pLDAPAuthNodeStruct->fServerName = aLDAPName;
pLDAPAuthNodeStruct->fDirectLDAPPort = ldapPort;
pLDAPAuthNodeStruct->fLDAPConfigTableIndex = *inOutLDAPConfigTableIndex;
siResult = BindProc( pLDAPAuthNodeStruct, nil, shouldCloseOld );
if (siResult == eDSNoErr)
{
*outLDAPHost = pLDAPAuthNodeStruct->fHost;
if ( shouldCloseOld )
{
ldap_unbind( inHost );
inHost = nil;
}
}
else
{
siResult = eDSAuthFailed;
}
}
if (pLDAPAuthNodeStruct != nil)
{
if (pLDAPAuthNodeStruct->fServerName != nil)
{
free(pLDAPAuthNodeStruct->fServerName); }
free(pLDAPAuthNodeStruct);
pLDAPAuthNodeStruct = nil;
}
}
else
{
fLDAPNodeOpenMutex.Signal();
siResult = eDSOpenNodeFailed;
}
return(siResult);
}
sInt32 CLDAPNode::RebindSession( char *inNodeName,
LDAP *inHost,
CLDAPv3Configs *inConfigFromXML,
LDAP **outLDAPHost )
{
sInt32 siResult = eDSNoErr;
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
string aNodeName(inNodeName);
fLDAPNodeOpenMutex.Wait();
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
if (pLDAPNodeStruct->fHost != nil)
{
ldap_unbind(pLDAPNodeStruct->fHost);
pLDAPNodeStruct->fHost = nil;
}
fLDAPNodeOpenMutex.Signal();
if (pLDAPNodeStruct->fLDAPSessionMutex != nil)
{
pLDAPNodeStruct->fLDAPSessionMutex->Wait();
}
siResult = BindProc( pLDAPNodeStruct );
if (pLDAPNodeStruct->fLDAPSessionMutex != nil)
{
pLDAPNodeStruct->fLDAPSessionMutex->Signal();
}
if (siResult == eDSNoErr)
{
*outLDAPHost = pLDAPNodeStruct->fHost;
pLDAPNodeStruct->fConnectionStatus = kConnectionSafe;
RetrieveServerMappingsIfRequired(pLDAPNodeStruct, inConfigFromXML);
}
}
else {
fLDAPNodeOpenMutex.Signal();
siResult = eDSOpenNodeFailed;
}
return(siResult);
}
sInt32 CLDAPNode::SimpleAuth( char *inNodeName,
char *inUserName,
void *inAuthCredential )
{
sInt32 siResult = eDSNoErr;
sLDAPNodeStruct *pLDAPAuthNodeStruct = nil;
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
string aNodeName(inNodeName);
fLDAPNodeOpenMutex.Wait();
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
pLDAPAuthNodeStruct = (sLDAPNodeStruct *) calloc(1, sizeof(sLDAPNodeStruct));
if (pLDAPNodeStruct->fLDAPConfigTableIndex != 0)
{
pLDAPAuthNodeStruct->fLDAPConfigTableIndex = pLDAPNodeStruct->fLDAPConfigTableIndex;
}
else
{
pLDAPAuthNodeStruct->fServerName = pLDAPNodeStruct->fServerName;
pLDAPAuthNodeStruct->fDirectLDAPPort = pLDAPNodeStruct->fDirectLDAPPort;
}
pLDAPAuthNodeStruct->fHost = nil; pLDAPAuthNodeStruct->fLDAPSessionMutex = nil;
pLDAPAuthNodeStruct->fUserName = inUserName;
pLDAPAuthNodeStruct->fAuthCredential = inAuthCredential;
siResult = BindProc( pLDAPAuthNodeStruct );
if (siResult != eDSNoErr)
{
siResult = eDSAuthFailed;
}
if (pLDAPAuthNodeStruct->fHost != nil)
{
ldap_unbind(pLDAPAuthNodeStruct->fHost);
}
free(pLDAPAuthNodeStruct);
}
else {
siResult = eDSAuthFailed;
}
fLDAPNodeOpenMutex.Signal();
return(siResult);
}
sInt32 CLDAPNode::RebindAuthSession( char *inNodeName,
LDAP *inHost,
char *inUserName,
void *inAuthCredential,
char *inAuthType,
uInt32 inLDAPConfigTableIndex,
LDAP **outLDAPHost )
{
sInt32 siResult = eDSNoErr;
sLDAPNodeStruct *pLDAPAuthNodeStruct = nil;
int ldapPort = LDAP_PORT;
char *aLDAPName = nil;
if (inHost != nil)
{
pLDAPAuthNodeStruct = (sLDAPNodeStruct *) calloc(1, sizeof(sLDAPNodeStruct));
siResult = ParseLDAPNodeName( inNodeName, &aLDAPName, &ldapPort );
if (siResult == eDSNoErr)
{
pLDAPAuthNodeStruct->fServerName = aLDAPName;
pLDAPAuthNodeStruct->fDirectLDAPPort = ldapPort;
pLDAPAuthNodeStruct->fHost = nil;
pLDAPAuthNodeStruct->fLDAPConfigTableIndex = inLDAPConfigTableIndex;
pLDAPAuthNodeStruct->fUserName = inUserName;
pLDAPAuthNodeStruct->fAuthCredential = inAuthCredential;
ldap_unbind(inHost);
siResult = BindProc( pLDAPAuthNodeStruct );
if (siResult == eDSNoErr)
{
*outLDAPHost = pLDAPAuthNodeStruct->fHost;
}
}
if (pLDAPAuthNodeStruct != nil)
{
if (pLDAPAuthNodeStruct->fServerName != nil)
{
free(pLDAPAuthNodeStruct->fServerName); }
free(pLDAPAuthNodeStruct);
pLDAPAuthNodeStruct = nil;
}
}
else
{
siResult = eDSOpenNodeFailed;
}
return(siResult);
}
sInt32 CLDAPNode::SafeClose ( char *inNodeName,
LDAP *inHost )
{
sInt32 siResult = eDSNoErr;
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
string aNodeName(inNodeName);
fLDAPNodeOpenMutex.Wait();
if (inHost != nil)
{
ldap_unbind( inHost );
}
else
{
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
pLDAPNodeStruct->fRefCount--;
if (pLDAPNodeStruct->fRefCount == 0 && pLDAPNodeStruct->fConnectionStatus == kConnectionSafe)
{
fLDAPNodeMap.erase(aNodeName);
CleanLDAPNodeStruct(pLDAPNodeStruct);
free(pLDAPNodeStruct);
}
}
}
fLDAPNodeOpenMutex.Signal();
return(siResult);
}
sInt32 CLDAPNode::ForcedSafeClose ( char *inNodeName)
{
sInt32 siResult = eDSNoErr;
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
string aNodeName(inNodeName);
fLDAPNodeOpenMutex.Wait();
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end() )
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
if (pLDAPNodeStruct->fConnectionStatus == kConnectionSafe)
{
if (pLDAPNodeStruct->fOperationsCount == 0)
{
fLDAPNodeMap.erase(aNodeName);
CleanLDAPNodeStruct(pLDAPNodeStruct);
free(pLDAPNodeStruct);
}
else
{
fLDAPNodeMap.erase(aNodeName);
fDeadPoolLDAPNodeVector.push_back(pLDAPNodeStruct);
}
}
}
fLDAPNodeOpenMutex.Signal();
return(siResult);
}
void CLDAPNode::GetSchema ( sLDAPContextData *inContext )
{
sInt32 siResult = eDSNoErr;
sLDAPConfigData *pConfig = nil;
LDAPMessage *LDAPResult = nil;
BerElement *ber = nil;
struct berval **bValues = nil;
char *pAttr = nil;
sObjectClassSchema *aOCSchema = nil;
bool bSkipToTag = true;
char *lineEntry = nil;
char *strtokContext = nil;
LDAP *aHost = nil;
if ( inContext != nil )
{
pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( inContext->fConfigTableIndex );
if (pConfig != nil)
{
aHost = LockSession(inContext);
if ( (aHost != nil) && !(pConfig->bOCBuilt) ) {
siResult = GetSchemaMessage( aHost, pConfig->fSearchTimeout, &LDAPResult);
if (siResult == eDSNoErr)
{
for ( pAttr = ldap_first_attribute (aHost, LDAPResult, &ber );
pAttr != NULL; pAttr = ldap_next_attribute(aHost, LDAPResult, ber ) )
{
if (( bValues = ldap_get_values_len (aHost, LDAPResult, pAttr )) != NULL)
{
ObjectClassMap *aOCClassMap = new(ObjectClassMap);
for (int i = 0; bValues[i] != NULL; i++ )
{
aOCSchema = nil;
if (lineEntry != nil) {
free(lineEntry);
lineEntry = nil;
}
lineEntry = (char *)calloc(1,bValues[i]->bv_len+1);
strcpy(lineEntry, bValues[i]->bv_val);
char *aToken = nil;
aToken = strtok_r(lineEntry,OCSEPCHARS, &strtokContext);
while ( (aToken != nil) && (strcmp(aToken,"NAME") != 0) )
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
}
if (aToken != nil)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken != nil)
{
if (aOCClassMap->find(aToken) == aOCClassMap->end())
{
aOCSchema = new(sObjectClassSchema);
(*aOCClassMap)[aToken] = aOCSchema;
}
}
}
if (aOCSchema == nil)
{
continue;
}
if (aToken == nil)
{
continue;
}
bSkipToTag = true;
while (bSkipToTag)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
break;
}
bSkipToTag = IsTokenNotATag(aToken);
if (bSkipToTag)
{
aOCSchema->fOtherNames.insert(aOCSchema->fOtherNames.begin(),aToken);
}
}
if (aToken == nil)
{
continue;
}
if (strcmp(aToken,"DESC") == 0)
{
bSkipToTag = true;
while (bSkipToTag)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
break;
}
bSkipToTag = IsTokenNotATag(aToken);
}
if (aToken == nil)
{
continue;
}
}
if (strcmp(aToken,"OBSOLETE") == 0)
{
bSkipToTag = true;
while (bSkipToTag)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
break;
}
bSkipToTag = IsTokenNotATag(aToken);
}
if (aToken == nil)
{
continue;
}
}
if (strcmp(aToken,"SUP") == 0)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
continue;
}
aOCSchema->fParentOCs.insert(aOCSchema->fParentOCs.begin(),aToken);
bSkipToTag = true;
while (bSkipToTag)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
break;
}
bSkipToTag = IsTokenNotATag(aToken);
if (bSkipToTag)
{
aOCSchema->fParentOCs.insert(aOCSchema->fParentOCs.begin(),aToken);
}
}
if (aToken == nil)
{
continue;
}
}
if (strcmp(aToken,"ABSTRACT") == 0)
{
aOCSchema->fType = 0;
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
continue;
}
}
if (strcmp(aToken,"STRUCTURAL") == 0)
{
aOCSchema->fType = 1;
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
continue;
}
}
if (strcmp(aToken,"AUXILIARY") == 0)
{
aOCSchema->fType = 2;
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
continue;
}
}
if (strcmp(aToken,"MUST") == 0)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
continue;
}
aOCSchema->fRequiredAttrs.insert(aOCSchema->fRequiredAttrs.begin(),aToken);
bSkipToTag = true;
while (bSkipToTag)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
break;
}
bSkipToTag = IsTokenNotATag(aToken);
if (bSkipToTag)
{
aOCSchema->fRequiredAttrs.insert(aOCSchema->fRequiredAttrs.begin(),aToken);
}
}
if (aToken == nil)
{
continue;
}
}
if (strcmp(aToken,"MAY") == 0)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
continue;
}
aOCSchema->fAllowedAttrs.insert(aOCSchema->fAllowedAttrs.begin(),aToken);
bSkipToTag = true;
while (bSkipToTag)
{
aToken = strtok_r(NULL,OCSEPCHARS, &strtokContext);
if (aToken == nil)
{
break;
}
bSkipToTag = IsTokenNotATag(aToken);
if (bSkipToTag)
{
aOCSchema->fAllowedAttrs.insert(aOCSchema->fAllowedAttrs.begin(),aToken);
}
}
if (aToken == nil)
{
continue;
}
}
}
if (lineEntry != nil) {
free(lineEntry);
lineEntry = nil;
}
ldap_value_free_len(bValues);
pConfig->fObjectClassSchema = aOCClassMap;
}
if (pAttr != nil)
{
ldap_memfree( pAttr );
}
}
if (ber != nil)
{
ber_free( ber, 0 );
}
ldap_msgfree( LDAPResult );
}
}
pConfig->bOCBuilt = true;
UnLockSession(inContext);
}
}
}
sInt32 CLDAPNode::ParseLDAPNodeName( char *inNodeName,
char **outLDAPName,
int *outLDAPPort )
{
sInt32 siResult = eDSNoErr;
char *portPos = nil;
uInt32 inLength = 0;
int ldapPort = LDAP_PORT;
char *ldapName = nil;
if (inNodeName != nil)
{
inLength = strlen(inNodeName);
portPos = strchr(inNodeName, ':');
if (portPos != nil)
{
portPos++;
if (portPos != nil)
{
ldapPort = strtoul(portPos,NULL,NULL);
if (ldapPort == 0)
{
ldapPort = LDAP_PORT;
}
inLength = inLength - strlen(portPos);
}
ldapName = (char *) calloc(1, inLength);
strncpy(ldapName, inNodeName, inLength-1);
}
else
{
ldapName = (char *) calloc(1, inLength+1);
strncpy(ldapName, inNodeName, inLength);
}
*outLDAPName = ldapName;
*outLDAPPort = ldapPort;
}
else
{
siResult = eDSNullParameter;
}
return(siResult);
}
sInt32 CLDAPNode::CleanLDAPNodeStruct ( sLDAPNodeStruct *inLDAPNodeStruct )
{
sInt32 siResult = eDSNoErr;
if (inLDAPNodeStruct != nil)
{
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Wait();
}
if (inLDAPNodeStruct->fHost != nil)
{
ldap_unbind( inLDAPNodeStruct->fHost );
inLDAPNodeStruct->fHost = nil;
}
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Signal();
delete(inLDAPNodeStruct->fLDAPSessionMutex);
inLDAPNodeStruct->fLDAPSessionMutex = nil;
}
if (inLDAPNodeStruct->fServerName != nil)
{
free( inLDAPNodeStruct->fServerName );
inLDAPNodeStruct->fServerName = nil;
}
if (inLDAPNodeStruct->fUserName != nil)
{
free( inLDAPNodeStruct->fUserName );
inLDAPNodeStruct->fUserName = nil;
}
if (inLDAPNodeStruct->fAuthCredential != nil)
{
free( inLDAPNodeStruct->fAuthCredential );
inLDAPNodeStruct->fAuthCredential = nil;
}
if (inLDAPNodeStruct->fAuthType != nil)
{
free( inLDAPNodeStruct->fAuthType );
inLDAPNodeStruct->fAuthType = nil;
}
inLDAPNodeStruct->fRefCount = 0;
inLDAPNodeStruct->fOperationsCount = 0;
inLDAPNodeStruct->fLDAPConfigTableIndex = 0;
inLDAPNodeStruct->fDirectLDAPPort = 389;
inLDAPNodeStruct->fConnectionStatus = kConnectionSafe;
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + 120;
inLDAPNodeStruct->fConnectionActiveCount = 0;
inLDAPNodeStruct->fIdleTOCount = 0;
inLDAPNodeStruct->fIdleTO = 4; inLDAPNodeStruct->fDelayRebindTry = 120;
}
return(siResult);
}
sInt32 CLDAPNode::BindProc ( sLDAPNodeStruct *inLDAPNodeStruct, CLDAPv3Configs *inConfigFromXML, bool bSessionBased, bool bForceBind )
{
sInt32 siResult = eDSNoErr;
int bindMsgId = 0;
int version = -1;
sLDAPConfigData *pConfig = nil;
char *ldapAcct = nil;
char *ldapPasswd = nil;
int openTO = kLDAPDefaultOpenCloseTimeoutInSeconds;
LDAP *inLDAPHost = inLDAPNodeStruct->fHost;
LDAPMessage *result = nil;
int ldapReturnCode = 0;
try
{
if ( inLDAPNodeStruct == nil ) throw( (sInt32)eDSNullParameter );
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Wait();
}
if (inLDAPHost == NULL)
{
if (( inLDAPNodeStruct->fLDAPConfigTableIndex < gLDAPConfigTableLen) && ( inLDAPNodeStruct->fLDAPConfigTableIndex >= 1 ))
{
pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( inLDAPNodeStruct->fLDAPConfigTableIndex );
if (pConfig != nil)
{
if ( (pConfig->bSecureUse) && (inLDAPNodeStruct->fUserName == nil) )
{
if (pConfig->fServerAccount != nil)
{
ldapAcct = new char[1+::strlen(pConfig->fServerAccount)];
::strcpy( ldapAcct, pConfig->fServerAccount );
}
if (pConfig->fServerPassword != nil)
{
ldapPasswd = new char[1+::strlen(pConfig->fServerPassword)];
::strcpy( ldapPasswd, pConfig->fServerPassword );
}
}
else
{
if (inLDAPNodeStruct->fUserName != nil)
{
ldapAcct = new char[1+::strlen(inLDAPNodeStruct->fUserName)];
::strcpy( ldapAcct, inLDAPNodeStruct->fUserName );
}
if (inLDAPNodeStruct->fAuthCredential != nil)
{
if (inLDAPNodeStruct->fAuthType != nil)
{
if (strcmp(inLDAPNodeStruct->fAuthType,kDSStdAuthClearText) == 0)
{
ldapPasswd = new char[1+::strlen((char*)(inLDAPNodeStruct->fAuthCredential))];
::strcpy( ldapPasswd, (char*)(inLDAPNodeStruct->fAuthCredential) );
}
}
else {
ldapPasswd = new char[1+::strlen((char*)(inLDAPNodeStruct->fAuthCredential))];
::strcpy( ldapPasswd, (char*)(inLDAPNodeStruct->fAuthCredential) );
}
}
}
openTO = pConfig->fOpenCloseTimeout;
}
}
if( !bForceBind && inLDAPNodeStruct->fConnectionStatus == kConnectionUnknown )
{
EnsureCheckFailedConnectionsThreadIsRunning();
struct mach_timebase_info timeBaseInfo;
uint64_t delay;
mach_timebase_info( &timeBaseInfo );
delay = (((uint64_t)(NSEC_PER_SEC * openTO) * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer);
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Signal();
}
mach_wait_until( mach_absolute_time() + delay );
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Wait();
}
if (pConfig != nil)
{
sReplicaInfo *replicaList = pConfig->fReplicaHosts;
while( replicaList != nil )
{
replicaList->bUsedLast = false;
replicaList = replicaList->fNext;
}
}
}
if( !bForceBind && inLDAPNodeStruct->fConnectionStatus != kConnectionSafe )
{
throw( (sInt32)eDSCannotAccessSession );
}
if (inLDAPNodeStruct->fLDAPConfigTableIndex != 0)
{
if (pConfig != nil)
{
inLDAPHost = InitLDAPConnection( inLDAPNodeStruct, pConfig, inConfigFromXML, bSessionBased );
}
}
else
{
inLDAPHost = ldap_init( inLDAPNodeStruct->fServerName, inLDAPNodeStruct->fDirectLDAPPort );
}
if ( inLDAPHost == nil )
{
LogFailedConnection("InitLDAPConnection or ldap_init failure", inLDAPNodeStruct->fServerName, inLDAPNodeStruct->fDelayRebindTry);
if (bForceBind)
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnsafe;
}
else
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
}
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
throw( (sInt32)eDSCannotAccessSession );
}
if (inLDAPNodeStruct->fHost == nil)
{
if (pConfig != nil)
{
if ( pConfig->bIsSSL )
{
int ldapOptVal = LDAP_OPT_X_TLS_HARD;
ldap_set_option(inLDAPHost, LDAP_OPT_X_TLS, &ldapOptVal);
}
ldap_set_option(inLDAPHost, LDAP_OPT_REFERRALS, (pConfig->bReferrals ? LDAP_OPT_ON : LDAP_OPT_OFF) );
}
version = LDAP_VERSION3;
ldap_set_option( inLDAPHost, LDAP_OPT_PROTOCOL_VERSION, &version );
ldapReturnCode = doSASLBindAttemptIfPossible( inLDAPHost, pConfig, ldapAcct, ldapPasswd );
if( ldapReturnCode != LDAP_LOCAL_ERROR && ldapReturnCode != LDAP_OTHER )
{
if( ldapReturnCode != LDAP_SUCCESS )
{
DBGLOG( kLogPlugin, "CLDAPNode::Failed doing SASL Authentication" );
if (bForceBind)
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnsafe;
}
else
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
}
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
throw( (sInt32)eDSCannotAccessSession );
}
}
else
{
DBGLOG( kLogPlugin, "CLDAPNode::SASL Authentication didn't work, failing through to bind" );
bindMsgId = ldap_bind( inLDAPHost, ldapAcct, ldapPasswd, LDAP_AUTH_SIMPLE );
struct timeval tv;
tv.tv_sec = (openTO ? openTO : kLDAPDefaultOpenCloseTimeoutInSeconds); tv.tv_usec = 0;
ldapReturnCode = ldap_result(inLDAPHost, bindMsgId, 0, &tv, &result);
if ( ldapReturnCode == -1 )
{
throw( (sInt32)eDSCannotAccessSession );
}
else if ( ldapReturnCode == 0 )
{
ldap_abandon(inLDAPHost, bindMsgId);
if ( (pConfig != nil) && (pConfig->fServerName != nil) )
{
LogFailedConnection("Bind timeout", pConfig->fServerName, inLDAPNodeStruct->fDelayRebindTry);
}
else
{
LogFailedConnection("Bind timeout", inLDAPNodeStruct->fServerName, inLDAPNodeStruct->fDelayRebindTry);
}
if (bForceBind)
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnsafe;
}
else
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
}
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
throw( (sInt32)eDSCannotAccessSession );
}
else if ( ldap_result2error(inLDAPHost, result, 1) != LDAP_SUCCESS )
{
if ( (pConfig != nil) && (pConfig->fServerName != nil) )
{
LogFailedConnection("Bind failure", pConfig->fServerName, inLDAPNodeStruct->fDelayRebindTry);;
}
else
{
LogFailedConnection("Bind failure", inLDAPNodeStruct->fServerName, inLDAPNodeStruct->fDelayRebindTry);
}
if (bForceBind)
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnsafe;
}
else
{
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
}
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
inLDAPNodeStruct->fHost = inLDAPHost;
throw( (sInt32)eDSCannotAccessSession );
}
}
inLDAPNodeStruct->fConnectionStatus = kConnectionSafe;
inLDAPNodeStruct->fHost = inLDAPHost;
}
result = nil;
}
}
catch ( sInt32 err )
{
siResult = err;
}
if (ldapAcct != nil)
{
delete (ldapAcct);
ldapAcct = nil;
}
if (ldapPasswd != nil)
{
delete (ldapPasswd);
ldapPasswd = nil;
}
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Signal();
}
return (siResult);
}
char** CLDAPNode::GetNamingContexts( LDAP *inHost, int inSearchTO, uInt32 *outCount )
{
sInt32 siResult = eDSRecordNotFound;
bool bResultFound = false;
int ldapMsgId = 0;
LDAPMessage *result = nil;
int ldapReturnCode = 0;
char *attrs[2] = {"namingContexts",NULL};
BerElement *ber = nil;
struct berval **bValues = nil;
char *pAttr = nil;
char **outMapSearchBases = nil;
*outCount = 0;
ldapReturnCode = ldap_search_ext( inHost,
"",
LDAP_SCOPE_BASE,
"(objectclass=*)",
attrs,
0,
NULL,
NULL,
0, 0,
&ldapMsgId );
if (ldapReturnCode == LDAP_SUCCESS)
{
bResultFound = true;
struct timeval tv;
tv.tv_usec = 0;
if (inSearchTO == 0)
{
tv.tv_sec = kLDAPDefaultOpenCloseTimeoutInSeconds; }
else
{
tv.tv_sec = inSearchTO;
}
ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, &tv, &result);
}
if ( (bResultFound) &&
( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) )
{
pAttr = ldap_first_attribute (inHost, result, &ber );
if (pAttr != nil)
{
if (( bValues = ldap_get_values_len (inHost, result, pAttr )) != NULL)
{
uInt32 valCount = 0;
for (int ii = 0; bValues[ii] != nil; ii++ )
{
valCount++;
}
outMapSearchBases = (char **) calloc( valCount+1, sizeof(char *));
for (int i = 0; (bValues[i] != nil) && (bValues[i]->bv_val != nil); i++ )
{
outMapSearchBases[i] = strdup(bValues[i]->bv_val);
(*outCount)++;
siResult = eDSNoErr;
}
ldap_value_free_len(bValues);
} ldap_memfree( pAttr );
}
if (ber != nil)
{
ber_free( ber, 0 );
}
ldap_msgfree( result );
result = nil;
} else if (ldapReturnCode == LDAP_TIMEOUT)
{
siResult = eDSServerTimeout;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
outMapSearchBases = (char **) -1; }
}
else
{
siResult = eDSRecordNotFound;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
DSSearchCleanUp(inHost, ldapMsgId);
return( outMapSearchBases );
}
sInt32 CLDAPNode::GetSchemaMessage ( LDAP *inHost, int inSearchTO, LDAPMessage **outResultMsg )
{
sInt32 siResult = eDSNoErr;
bool bResultFound = false;
int ldapMsgId = 0;
LDAPMessage *result = nil;
int ldapReturnCode = 0;
char *sattrs[2] = {"subschemasubentry",NULL};
char *attrs[2] = {"objectclasses",NULL};
char *subschemaDN = nil;
BerElement *ber = nil;
struct berval **bValues = nil;
char *pAttr = nil;
try
{
if ( (ldapMsgId = ldap_search( inHost, "", LDAP_SCOPE_BASE, "(objectclass=*)", sattrs, 0) ) == -1 )
{
bResultFound = false;
}
else
{
bResultFound = true;
struct timeval tv;
tv.tv_usec = 0;
if (inSearchTO == 0)
{
tv.tv_sec = kLDAPDefaultSearchTimeoutInSeconds; }
else
{
tv.tv_sec = inSearchTO;
}
ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, &tv, &result);
}
if ( (bResultFound) &&
( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) )
{
siResult = eDSNoErr;
for ( pAttr = ldap_first_attribute (inHost, result, &ber );
pAttr != NULL; pAttr = ldap_next_attribute(inHost, result, ber ) )
{
if (( bValues = ldap_get_values_len (inHost, result, pAttr )) != NULL)
{
if ( bValues[0] != NULL )
{
subschemaDN = (char *) calloc(1, bValues[0]->bv_len + 1);
strcpy(subschemaDN,bValues[0]->bv_val);
}
ldap_value_free_len(bValues);
}
if (pAttr != nil)
{
ldap_memfree( pAttr );
}
}
if (ber != nil)
{
ber_free( ber, 0 );
}
ldap_msgfree( result );
result = nil;
} else if (ldapReturnCode == LDAP_TIMEOUT)
{
siResult = eDSServerTimeout;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
else
{
siResult = eDSRecordNotFound;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
DSSearchCleanUp(inHost, ldapMsgId);
if (subschemaDN != nil)
{
if ( (ldapMsgId = ldap_search( inHost, subschemaDN, LDAP_SCOPE_BASE, "(objectclass=subSchema)", attrs, 0) ) == -1 )
{
bResultFound = false;
}
else
{
bResultFound = true;
struct timeval tv;
tv.tv_usec = 0;
if (inSearchTO == 0)
{
tv.tv_sec = kLDAPDefaultSearchTimeoutInSeconds; }
else
{
tv.tv_sec = inSearchTO;
}
ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, &tv, &result);
}
free(subschemaDN);
subschemaDN = nil;
if ( (bResultFound) &&
( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) )
{
siResult = eDSNoErr;
} else if (ldapReturnCode == LDAP_TIMEOUT)
{
siResult = eDSServerTimeout;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
else
{
siResult = eDSRecordNotFound;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
DSSearchCleanUp(inHost, ldapMsgId);
}
}
catch ( sInt32 err )
{
siResult = err;
}
if (result != nil)
{
*outResultMsg = result;
}
return( siResult );
}
bool CLDAPNode::IsTokenNotATag ( char *inToken )
{
if (inToken == nil)
{
return true;
}
switch(*inToken)
{
case 'N':
case 'D':
case 'O':
case 'S':
case 'A':
case 'M':
case 'X':
if (strcmp(inToken,"DESC") == 0)
{
return false;
}
if (strcmp(inToken,"SUP") == 0)
{
return false;
}
if (strlen(inToken) > 7)
{
if (strcmp(inToken,"OBSOLETE") == 0)
{
return false;
}
if (strcmp(inToken,"ABSTRACT") == 0)
{
return false;
}
if (strcmp(inToken,"STRUCTURAL") == 0)
{
return false;
}
if (strcmp(inToken,"AUXILIARY") == 0)
{
return false;
}
if (strcmp(inToken,"X-ORIGIN") == 0) {
return false;
}
}
if (strcmp(inToken,"MUST") == 0)
{
return false;
}
if (strcmp(inToken,"MAY") == 0)
{
return false;
}
if (strcmp(inToken,"NAME") == 0)
{
return false;
}
break;
default:
break;
}
return( true );
}
LDAP* CLDAPNode::LockSession( sLDAPContextData *inContext )
{
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
if (inContext != nil)
{
inContext->fLDAPNodeStruct = nil;
if (inContext->authCallActive)
{
if (inContext->fLDAPSessionMutex != nil)
{
inContext->fLDAPSessionMutex->Wait();
}
return inContext->fHost;
}
else
{
string aNodeName(inContext->fName);
fLDAPNodeOpenMutex.Wait();
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
pLDAPNodeStruct->fRefCount++;
pLDAPNodeStruct->fOperationsCount++;
}
fLDAPNodeOpenMutex.Signal();
if (pLDAPNodeStruct != nil)
{
if (pLDAPNodeStruct->fLDAPSessionMutex != nil)
{
pLDAPNodeStruct->fLDAPSessionMutex->Wait();
}
inContext->fLDAPNodeStruct = pLDAPNodeStruct;
return pLDAPNodeStruct->fHost;
}
}
}
return nil;
}
void CLDAPNode::UnLockSession( sLDAPContextData *inContext, bool inHasFailed, bool inNewMutex )
{
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
DSMutexSemaphore *aMutex = nil;
sLDAPNodeStruct *aLDAPNodeStruct = nil;
if (inContext != nil)
{
if ( (inContext->authCallActive) && !inNewMutex )
{
if (inContext->fLDAPSessionMutex != nil)
{
inContext->fLDAPSessionMutex->Signal();
}
}
else
{
if ( (inContext->fLDAPNodeStruct != nil) && (inContext->fLDAPNodeStruct->fLDAPSessionMutex != nil) )
{
if (inHasFailed)
{
LogFailedConnection("Search connection failure", inContext->fLDAPNodeStruct->fServerName, inContext->fLDAPNodeStruct->fDelayRebindTry);
inContext->fLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
inContext->fLDAPNodeStruct->fDelayedBindTime = time( nil ) + inContext->fLDAPNodeStruct->fDelayRebindTry;
}
aMutex = inContext->fLDAPNodeStruct->fLDAPSessionMutex;
aLDAPNodeStruct = inContext->fLDAPNodeStruct;
inContext->fLDAPNodeStruct = nil;
aMutex->Signal();
string aNodeName(inContext->fName);
fLDAPNodeOpenMutex.Wait();
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
if (pLDAPNodeStruct != nil)
{
pLDAPNodeStruct->fRefCount--;
pLDAPNodeStruct->fOperationsCount--;
if (pLDAPNodeStruct->fRefCount == 0 && pLDAPNodeStruct->fConnectionStatus == kConnectionSafe)
{
CleanLDAPNodeStruct(pLDAPNodeStruct);
fLDAPNodeMap.erase(aNodeName);
free(pLDAPNodeStruct);
}
}
}
else
{
for ( LDAPNodeVectorI iter = fDeadPoolLDAPNodeVector.begin(); iter != fDeadPoolLDAPNodeVector.end(); ++iter)
{
if ( *iter == aLDAPNodeStruct )
{
aLDAPNodeStruct->fOperationsCount--;
if (aLDAPNodeStruct->fOperationsCount == 0 && aLDAPNodeStruct->fConnectionStatus == kConnectionSafe)
{
CleanLDAPNodeStruct(aLDAPNodeStruct);
fDeadPoolLDAPNodeVector.erase(iter);
free(aLDAPNodeStruct);
}
break;
}
}
}
fLDAPNodeOpenMutex.Signal();
}
}
}
}
void CLDAPNode::CheckIdles( void )
{
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
bool bShouldWeCheck = false;
fLDAPNodeOpenMutex.Wait();
for (aLDAPNodeMapI = fLDAPNodeMap.begin(); aLDAPNodeMapI != fLDAPNodeMap.end(); ++aLDAPNodeMapI)
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
if (pLDAPNodeStruct->fConnectionStatus != kConnectionSafe)
{
bShouldWeCheck = true;
}
if (pLDAPNodeStruct->fConnectionActiveCount == 0) {
if (pLDAPNodeStruct->fIdleTOCount == pLDAPNodeStruct->fIdleTO) {
if (pLDAPNodeStruct->fHost != nil)
{
ldap_unbind( pLDAPNodeStruct->fHost ); pLDAPNodeStruct->fHost = nil;
}
pLDAPNodeStruct->fIdleTOCount = 0;
}
else
{
pLDAPNodeStruct->fIdleTOCount++;
}
}
}
if (bShouldWeCheck)
{
EnsureCheckFailedConnectionsThreadIsRunning();
}
fLDAPNodeOpenMutex.Signal();
}
void CLDAPNode::CheckFailed( void )
{
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
LDAPNodeMap aLDAPNodeMap;
fLDAPNodeOpenMutex.Wait();
for (aLDAPNodeMapI = fLDAPNodeMap.begin(); aLDAPNodeMapI != fLDAPNodeMap.end(); ++aLDAPNodeMapI)
{
if( aLDAPNodeMapI->second->fConnectionStatus != kConnectionSafe ) {
pLDAPNodeStruct = (sLDAPNodeStruct *) aLDAPNodeMapI->second;
if( pLDAPNodeStruct->fHost != nil )
{
ldap_unbind_ext( pLDAPNodeStruct->fHost, NULL, NULL );
pLDAPNodeStruct->fHost = NULL;
}
aLDAPNodeMap[aLDAPNodeMapI->first] = pLDAPNodeStruct;
}
}
fLDAPNodeOpenMutex.Signal();
for (aLDAPNodeMapI = aLDAPNodeMap.begin(); aLDAPNodeMapI != aLDAPNodeMap.end(); ++aLDAPNodeMapI) {
pLDAPNodeStruct = (sLDAPNodeStruct *) aLDAPNodeMapI->second;
if( pLDAPNodeStruct->fConnectionStatus == kConnectionUnknown || time( nil ) > pLDAPNodeStruct->fDelayedBindTime ) {
BindProc( pLDAPNodeStruct, nil, false, true );
}
}
}
void CLDAPNode::NetTransition( void )
{
fLDAPNodeOpenMutex.Wait();
for (uInt32 iTableIndex=1; iTableIndex<gLDAPConfigTableLen; iTableIndex++)
{
sLDAPConfigData *pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( iTableIndex );
if (pConfig != nil)
{
pConfig->bBuildReplicaList = true;
} }
if( (fCheckThreadActive == false) && (fLDAPNodeMap.size() > 0) )
{
LDAPNodeMapI aLDAPNodeMapI;
for (aLDAPNodeMapI = fLDAPNodeMap.begin(); aLDAPNodeMapI != fLDAPNodeMap.end(); ++aLDAPNodeMapI)
{
sLDAPNodeStruct *pLDAPNodeStruct = aLDAPNodeMapI->second;
pLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
pLDAPNodeStruct->fDelayedBindTime = nil;
if ( pLDAPNodeStruct->fHost != nil ) {
ldap_unbind( pLDAPNodeStruct->fHost ); pLDAPNodeStruct->fHost = nil;
}
}
EnsureCheckFailedConnectionsThreadIsRunning();
}
fLDAPNodeOpenMutex.Signal();
}
void CLDAPNode::ActiveConnection( char *inNodeName )
{
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
if (inNodeName != nil)
{
fLDAPNodeOpenMutex.Wait();
string aNodeName(inNodeName);
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
pLDAPNodeStruct->fConnectionActiveCount++;
pLDAPNodeStruct->fIdleTOCount = 0;
}
fLDAPNodeOpenMutex.Signal();
}
}
void CLDAPNode::IdleConnection( char *inNodeName )
{
sLDAPNodeStruct *pLDAPNodeStruct = nil;
LDAPNodeMapI aLDAPNodeMapI;
if (inNodeName != nil)
{
fLDAPNodeOpenMutex.Wait();
string aNodeName(inNodeName);
aLDAPNodeMapI = fLDAPNodeMap.find(aNodeName);
if (aLDAPNodeMapI != fLDAPNodeMap.end())
{
pLDAPNodeStruct = aLDAPNodeMapI->second;
if (pLDAPNodeStruct->fConnectionActiveCount != 0)
{
pLDAPNodeStruct->fConnectionActiveCount--;
}
}
fLDAPNodeOpenMutex.Signal();
}
}
LDAP* CLDAPNode::InitLDAPConnection( sLDAPNodeStruct *inLDAPNodeStruct, sLDAPConfigData *inConfig, CLDAPv3Configs *inConfigFromXML, bool bInNeedWriteable )
{
sReplicaInfo *inOutList = nil;
sReplicaInfo *tailList = nil;
struct addrinfo *addrList;
LDAP *outHost = nil;
sInt32 replicaSearchResult = eDSNoErr;
if (inConfig->bBuildReplicaList)
{
CFStringRef serverStrRef = CFStringCreateWithCString( NULL, inConfig->fServerName, kCFStringEncodingUTF8 );
if (inConfig->fReplicaHostnames == nil)
{
inConfig->fReplicaHostnames = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
}
if( inConfig->fReplicaHostnames != nil && CFArrayGetCount(inConfig->fReplicaHostnames) == 0 )
{
CFArrayAppendValue(inConfig->fReplicaHostnames, serverStrRef);
}
CFIndex numReps = CFArrayGetCount(inConfig->fReplicaHostnames);
for (CFIndex indexToRep=0; indexToRep < numReps; indexToRep++ )
{
CFStringRef replicaStrRef = (CFStringRef)::CFArrayGetValueAtIndex( inConfig->fReplicaHostnames, indexToRep );
addrList = ResolveHostName(replicaStrRef, inConfig->fServerPort);
sReplicaInfo* newInfo = (sReplicaInfo *)calloc(1, sizeof(sReplicaInfo));
if (inOutList == nil)
{
inOutList = newInfo;
tailList = newInfo;
}
else
{
tailList->fNext = newInfo;
tailList = tailList->fNext;
}
newInfo->fAddrInfo = addrList;
newInfo->hostname = CFStringCreateCopy( kCFAllocatorDefault, replicaStrRef );
}
if( numReps == 1 )
{
inOutList->bWriteable = true;
}
replicaSearchResult = eDSNoStdMappingAvailable;
if( replicaSearchResult != eDSNoErr )
{
replicaSearchResult = RetrieveDefinedReplicas(inLDAPNodeStruct, inConfigFromXML, inConfig->fServerName, inConfig->fReplicaHostnames, inConfig->fWriteableHostnames, inConfig->fServerPort, &inOutList);
}
if ( replicaSearchResult == eDSNoErr || replicaSearchResult == eDSNoStdMappingAvailable || inConfig->fReplicaHosts == nil )
{
if( inOutList )
{
FreeReplicaList( inConfig->fReplicaHosts );
inConfig->fReplicaHosts = inOutList;
}
}
inConfig->bBuildReplicaList = false;
if (inConfig->fWriteableHostnames == nil)
{
inConfig->fWriteableHostnames = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(inConfig->fWriteableHostnames, serverStrRef);
}
if ( inConfigFromXML != nil )
{
inConfigFromXML->UpdateReplicaList(inConfig->fServerName, inConfig->fReplicaHostnames, inConfig->fWriteableHostnames);
}
CFRelease(serverStrRef);
}
CFIndex numInRepsList = 0;
CFIndex numInAddrInfoList = 0;
if (inConfig->fReplicaHostnames != nil)
{
numInRepsList = CFArrayGetCount(inConfig->fReplicaHostnames);
}
sReplicaInfo* anAddrInfo = inConfig->fReplicaHosts;
while (anAddrInfo != nil)
{
numInAddrInfoList++;
anAddrInfo = anAddrInfo->fNext;
}
if (( numInRepsList != 0 ) && ( numInRepsList != numInAddrInfoList ))
{
CFRange rangeOfWrites = CFRangeMake( 0, (inConfig->fWriteableHostnames ? CFArrayGetCount(inConfig->fWriteableHostnames) : 0) );
for (CFIndex indexToRep=0; indexToRep < numInRepsList; indexToRep++ )
{
CFStringRef replicaStrRef = (CFStringRef)::CFArrayGetValueAtIndex( inConfig->fReplicaHostnames, indexToRep );
sReplicaInfo* newInfo = (sReplicaInfo *)calloc(1, sizeof(sReplicaInfo));
if (indexToRep == 0)
{
anAddrInfo = newInfo;
tailList = newInfo;
}
else
{
tailList->fNext = newInfo;
tailList = tailList->fNext;
}
newInfo->fAddrInfo = ResolveHostName(replicaStrRef, inConfig->fServerPort);;
newInfo->hostname = CFStringCreateCopy( kCFAllocatorDefault, replicaStrRef );
if( inConfig->fWriteableHostnames != nil && CFArrayContainsValue(inConfig->fWriteableHostnames, rangeOfWrites, replicaStrRef) )
{
newInfo->bWriteable = true;
}
}
if (anAddrInfo != nil) {
FreeReplicaList( inConfig->fReplicaHosts );
inConfig->fReplicaHosts = anAddrInfo;
}
}
if ( (replicaSearchResult != eDSCannotAccessSession) && (inLDAPNodeStruct->fHost == nil) )
{
if (inConfig->fReplicaHosts != nil)
{
outHost = EstablishConnection( inConfig->fReplicaHosts, inConfig->fServerPort, inConfig->fOpenCloseTimeout, bInNeedWriteable );
if ( (outHost == nil) && (bInNeedWriteable) )
{
if ((strcmp( inConfig->fServerName, "127.0.0.1" ) == 0)
|| (strcmp( inConfig->fServerName, "localhost" ) == 0))
{
if (gServerOS && !LocalServerIsLDAPReplica())
{
outHost = ldap_init( "127.0.0.1", inConfig->fServerPort );
}
}
else
{
outHost = ldap_init( inConfig->fServerName, inConfig->fServerPort );
}
}
}
else {
outHost = ldap_init( inConfig->fServerName, inConfig->fServerPort );
}
}
if (inLDAPNodeStruct->fHost != nil)
{
outHost = inLDAPNodeStruct->fHost;
}
return(outHost);
}
struct addrinfo* CLDAPNode::ResolveHostName( CFStringRef inServerNameRef, int inPortNumber )
{
struct addrinfo hints;
struct addrinfo *res = nil;
char portString[32] = {0};
char serverName[512] = {0};
if (CFStringGetCString(inServerNameRef, serverName, 512, kCFStringEncodingUTF8))
{
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM;
sprintf( portString, "%d", inPortNumber );
if ( getaddrinfo(serverName, portString, &hints, &res) != 0 )
{
res = nil;
}
}
return(res);
}
LDAP* CLDAPNode::EstablishConnection( sReplicaInfo *inList, int inPort, int inOpenTimeout, bool bInNeedWriteable )
{
const int maxSockets = 512; LDAP *outHost = nil;
sReplicaInfo *lastUsedReplica = nil;
sReplicaInfo *resolvedRepIter = nil;
struct addrinfo *resolvedAddrIter = nil;
int val = 1;
int len = sizeof(val);
struct timeval recvTimeoutVal = { inOpenTimeout, 0 };
struct timeval recheckTimeoutVal = { 1, 0 };
struct timeval quickCheck = { 0, 3000 }; struct timeval pollValue = { 0, 0 };
int sockCount = 0;
fd_set fdset, fdwrite, fdread;
int fcntlFlags = 0;
char *goodHostAddress = NULL;
int *sockList = nil;
sReplicaInfo **replicaPointers = nil;
struct addrinfo **addrinfoPointers = nil;
int sockIter;
bool bReachableAddresses = false;
bool bTrySelect = false;
if (inPort == 0)
{
inPort = 389; }
if( inList == NULL )
return NULL;
sockList = (int *)calloc( maxSockets, sizeof(int) );
replicaPointers = (sReplicaInfo **)calloc( maxSockets, sizeof(sReplicaInfo *) );
addrinfoPointers = (struct addrinfo **)calloc( maxSockets, sizeof(struct addrinfo *) );
SetSockList( sockList, maxSockets, false );
FD_ZERO( &fdset );
for (resolvedRepIter = inList; resolvedRepIter != nil; resolvedRepIter = resolvedRepIter->fNext)
{
if ( !bInNeedWriteable || ( bInNeedWriteable && resolvedRepIter->bWriteable ))
{
for (resolvedAddrIter = resolvedRepIter->fAddrInfo; resolvedAddrIter != nil && sockCount < maxSockets; resolvedAddrIter = resolvedAddrIter->ai_next)
{
if( bReachableAddresses == false )
{
bReachableAddresses = ReachableAddress( resolvedAddrIter );
}
if( resolvedRepIter->bUsedLast == true )
{
resolvedRepIter->bUsedLast = false;
lastUsedReplica = resolvedRepIter;
}
else
{
replicaPointers[sockCount] = resolvedRepIter;
addrinfoPointers[sockCount] = resolvedAddrIter;
sockCount++;
}
}
}
}
if( lastUsedReplica == NULL && bReachableAddresses == false && sockCount > 0 )
{
struct mach_timebase_info timeBaseInfo;
mach_timebase_info( &timeBaseInfo );
int iReachableCount = 0;
uint64_t delay = (((uint64_t)NSEC_PER_SEC * (uint64_t)timeBaseInfo.denom) / (uint64_t)timeBaseInfo.numer);
while( bReachableAddresses == false && iReachableCount < (inOpenTimeout >> 1) )
{
mach_wait_until( mach_absolute_time() + delay );
iReachableCount++;
int iCount;
for( iCount = 0; iCount < sockCount && bReachableAddresses == false; iCount++ )
{
bReachableAddresses = ReachableAddress( addrinfoPointers[iCount] );
}
}
}
if( bReachableAddresses )
{
if (lastUsedReplica != nil)
{
for (resolvedAddrIter = lastUsedReplica->fAddrInfo; resolvedAddrIter != nil && goodHostAddress == nil; resolvedAddrIter = resolvedAddrIter->ai_next)
{
if( ReachableAddress(resolvedAddrIter) )
{
goodHostAddress = LDAPWithBlockingSocket( resolvedAddrIter, inOpenTimeout );
if( goodHostAddress )
{
DBGLOG2( kLogPlugin, "CLDAPNode::EstablishConnection - Previous replica with IP Address = %s responded for %s", goodHostAddress, (bInNeedWriteable ? "write" : "read") );
}
}
}
}
for( sockIter = 0; sockIter < sockCount && goodHostAddress == nil; sockIter++ )
{
struct addrinfo *tmpAddress = addrinfoPointers[sockIter];
if( ReachableAddress(tmpAddress) )
{
if( IsLocalAddress( tmpAddress ) )
{
goodHostAddress = LDAPWithBlockingSocket( tmpAddress, inOpenTimeout );
if( goodHostAddress )
{
lastUsedReplica = replicaPointers[sockIter];
DBGLOG2( kLogPlugin, "CLDAPNode::EstablishConnection - Attempting to use local address = %s for %s", goodHostAddress, (bInNeedWriteable ? "write" : "read") );
} else {
char *tempaddress = ConvertToIPAddress( addrinfoPointers[sockIter] );
if( tempaddress ) {
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Failed local address connect to = %s", tempaddress );
free( tempaddress );
}
}
}
else
{
int aSock = socket( tmpAddress->ai_family, tmpAddress->ai_socktype, tmpAddress->ai_protocol );
if( aSock != -1 )
{
setsockopt( aSock, SOL_SOCKET, SO_NOSIGPIPE, &val, len );
setsockopt( aSock, SOL_SOCKET, SO_RCVTIMEO, &recvTimeoutVal, sizeof(recvTimeoutVal) );
fcntlFlags = fcntl( aSock, F_GETFL, 0 );
if( fcntlFlags != -1 )
{
if( fcntl(aSock, F_SETFL, fcntlFlags | O_NONBLOCK) != -1 )
{
sockList[sockIter] = aSock;
if (connect(aSock, tmpAddress->ai_addr, tmpAddress->ai_addrlen) == -1)
{
FD_SET( aSock, &fdset );
bTrySelect = true;
char *tempaddress = ConvertToIPAddress( addrinfoPointers[sockIter] );
if( tempaddress ) {
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Attempting Replica connect to = %s", tempaddress );
free( tempaddress );
}
}
else
{
goodHostAddress = ConvertToIPAddress( tmpAddress );
if( goodHostAddress ) {
lastUsedReplica = replicaPointers[sockIter];
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Immediate Response to = %s", goodHostAddress );
}
}
}
else
{
close( aSock );
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Unable to do non-blocking connect for socket = %d", aSock );
}
}
else
{
close( aSock );
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Unable to do get GETFL = %d", aSock );
}
}
}
}
else
{
char *tempaddress = ConvertToIPAddress( addrinfoPointers[sockIter] );
if( tempaddress )
{
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Address not reachable %s", tempaddress );
free( tempaddress );
}
}
if( bTrySelect )
{
FD_COPY( &fdset, &fdwrite );
FD_COPY( &fdset, &fdread );
if( select( FD_SETSIZE, NULL, &fdwrite, NULL, &quickCheck ) > 0 )
{
select( FD_SETSIZE, &fdread, NULL, NULL, &pollValue );
int checkIter;
for( checkIter = 0; checkIter <= sockIter; checkIter++ )
{
int aSock = sockList[checkIter];
if( aSock != -1 && FD_ISSET(aSock, &fdwrite) && !FD_ISSET(aSock, &fdread) )
{
goodHostAddress = ConvertToIPAddress( addrinfoPointers[checkIter] );
if( goodHostAddress )
{
lastUsedReplica = replicaPointers[checkIter];
DBGLOG( kLogPlugin, "CLDAPNode::EstablishConnection - Got quick response from LDAP Replica");
break;
}
}
else if( aSock != -1 && FD_ISSET(aSock, &fdwrite) && FD_ISSET(aSock, &fdread) )
{
FD_CLR( aSock, &fdset );
char *tmpHostAddr = ConvertToIPAddress( addrinfoPointers[checkIter] );
if( tmpHostAddr ) {
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Quick Check Bad socket to host %s clearing from poll", tmpHostAddr );
break;
}
}
}
}
}
}
int iterTry = 0;
while( goodHostAddress == NULL && iterTry++ < inOpenTimeout && bTrySelect )
{
FD_COPY( &fdset, &fdwrite ); FD_COPY( &fdset, &fdread );
recheckTimeoutVal.tv_sec = 1;
if( select(FD_SETSIZE, NULL, &fdwrite, NULL, &recheckTimeoutVal) > 0 )
{
int checkIter;
select( FD_SETSIZE, &fdread, NULL, NULL, &pollValue );
for( checkIter = 0; checkIter < sockCount; checkIter++ )
{
int aSock = sockList[checkIter];
if( aSock != -1 && FD_ISSET(aSock, &fdwrite) && !FD_ISSET(aSock, &fdread) )
{
goodHostAddress = ConvertToIPAddress( addrinfoPointers[checkIter] );
if( goodHostAddress ) {
lastUsedReplica = replicaPointers[checkIter];
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Got a response from LDAP Replica %s", goodHostAddress );
break;
}
}
else if( aSock != -1 && FD_ISSET(aSock, &fdwrite) && FD_ISSET(aSock, &fdread) )
{
FD_CLR( aSock, &fdset );
char *tmpHostAddr = ConvertToIPAddress( addrinfoPointers[checkIter] );
if( tmpHostAddr ) {
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Bad socket to host %s clearing from poll", tmpHostAddr );
break;
}
}
}
}
}
if( goodHostAddress )
{
outHost = ldap_init( goodHostAddress, inPort );
if (outHost != nil)
{
if( lastUsedReplica )
{
lastUsedReplica->bUsedLast = true;
}
DBGLOG2( kLogPlugin, "CLDAPNode::EstablishConnection - Using replica with IP Address = %s for %s", goodHostAddress, (bInNeedWriteable ? "write" : "read") );
}
else
{
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - ldap_init failed for %s", goodHostAddress );
}
free( goodHostAddress );
}
else
{
DBGLOG1( kLogPlugin, "CLDAPNode::EstablishConnection - Could not establish connection for %s", (bInNeedWriteable ? "write" : "read") );
}
}
else
{
DBGLOG( kLogPlugin, "CLDAPNode::EstablishConnection - No reachable addresses, possibly no IP addresses" );
}
SetSockList( sockList, sockCount, true );
if (sockList != nil)
{
free(sockList);
}
if (replicaPointers != nil)
{
free(replicaPointers);
}
if (addrinfoPointers != nil)
{
free(addrinfoPointers);
}
return(outHost);
}
sInt32 CLDAPNode::RetrieveDefinedReplicas( sLDAPNodeStruct *inLDAPNodeStruct, CLDAPv3Configs *inConfigFromXML, char *inConfigServerString, CFMutableArrayRef &inOutRepList, CFMutableArrayRef &inOutWriteableList, int inPort, sReplicaInfo **inOutList )
{
LDAP *outHost = nil;
CFMutableArrayRef aRepList = NULL;
CFMutableArrayRef aWriteableList = NULL;
bool bMessageFound = false;
sInt32 foundResult = eDSRecordNotFound;
sReplicaInfo *aList = nil;
sReplicaInfo *oldList = nil;
sLDAPConfigData *pConfig = nil;
int openTimeout = kLDAPDefaultOpenCloseTimeoutInSeconds;
int searchTimeout = 30; int version = -1;
int bindMsgId = 0;
char *ldapAcct = nil;
char *ldapPasswd = nil;
LDAPMessage *result = nil;
int ldapReturnCode = 0;
try
{
if ( inLDAPNodeStruct != nil )
{
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Wait();
}
if (( inLDAPNodeStruct->fLDAPConfigTableIndex < gLDAPConfigTableLen) && ( inLDAPNodeStruct->fLDAPConfigTableIndex >= 1 ))
{
pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( inLDAPNodeStruct->fLDAPConfigTableIndex );
if (pConfig != nil)
{
if ( (pConfig->bSecureUse) && (inLDAPNodeStruct->fUserName == nil) )
{
if (pConfig->fServerAccount != nil)
{
ldapAcct = new char[1+::strlen(pConfig->fServerAccount)];
::strcpy( ldapAcct, pConfig->fServerAccount );
}
if (pConfig->fServerPassword != nil)
{
ldapPasswd = new char[1+::strlen(pConfig->fServerPassword)];
::strcpy( ldapPasswd, pConfig->fServerPassword );
}
}
else
{
if (inLDAPNodeStruct->fUserName != nil)
{
ldapAcct = new char[1+::strlen(inLDAPNodeStruct->fUserName)];
::strcpy( ldapAcct, inLDAPNodeStruct->fUserName );
}
if (inLDAPNodeStruct->fAuthCredential != nil)
{
if (inLDAPNodeStruct->fAuthType != nil)
{
if (strcmp(inLDAPNodeStruct->fAuthType,kDSStdAuthClearText) == 0)
{
ldapPasswd = new char[1+::strlen((char*)(inLDAPNodeStruct->fAuthCredential))];
::strcpy( ldapPasswd, (char*)(inLDAPNodeStruct->fAuthCredential) );
}
}
else {
ldapPasswd = new char[1+::strlen((char*)(inLDAPNodeStruct->fAuthCredential))];
::strcpy( ldapPasswd, (char*)(inLDAPNodeStruct->fAuthCredential) );
}
}
}
openTimeout = pConfig->fOpenCloseTimeout;
searchTimeout = pConfig->fSearchTimeout;
}
}
if (inLDAPNodeStruct->fLDAPSessionMutex != nil)
{
inLDAPNodeStruct->fLDAPSessionMutex->Signal();
}
}
outHost = EstablishConnection( *inOutList, inPort, openTimeout, false );
if (outHost != nil)
{
if (pConfig != nil)
{
if ( pConfig->bIsSSL )
{
int ldapOptVal = LDAP_OPT_X_TLS_HARD;
ldap_set_option(outHost, LDAP_OPT_X_TLS, &ldapOptVal);
}
ldap_set_option(outHost, LDAP_OPT_REFERRALS, (pConfig->bReferrals ? LDAP_OPT_ON : LDAP_OPT_OFF) );
}
version = LDAP_VERSION3;
ldap_set_option( outHost, LDAP_OPT_PROTOCOL_VERSION, &version );
ldapReturnCode = doSASLBindAttemptIfPossible( outHost, pConfig, ldapAcct, ldapPasswd );
if( ldapReturnCode != LDAP_LOCAL_ERROR && ldapReturnCode != LDAP_OTHER )
{
if( ldapReturnCode != LDAP_SUCCESS )
{
DBGLOG( kLogPlugin, "CLDAPNode::Failed doing SASL Authentication in Replica retrieval" );
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
throw( (sInt32)eDSCannotAccessSession );
}
}
else
{
bindMsgId = ldap_bind( outHost, ldapAcct, ldapPasswd, LDAP_AUTH_SIMPLE );
if (openTimeout == 0)
{
ldapReturnCode = ldap_result(outHost, bindMsgId, 0, NULL, &result);
}
else
{
struct timeval tv;
tv.tv_sec = openTimeout;
tv.tv_usec = 0;
ldapReturnCode = ldap_result(outHost, bindMsgId, 0, &tv, &result);
}
if ( ldapReturnCode == -1 )
{
throw( (sInt32)eDSCannotAccessSession );
}
else if ( ldapReturnCode == 0 )
{
ldap_abandon(outHost, bindMsgId);
if ( (pConfig != nil) && (pConfig->fServerName != nil) )
{
LogFailedConnection("Bind timeout in Replica retrieval", pConfig->fServerName, inLDAPNodeStruct->fDelayRebindTry);
}
else
{
LogFailedConnection("Bind timeout in Replica retrieval", inLDAPNodeStruct->fServerName, inLDAPNodeStruct->fDelayRebindTry);
}
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
throw( (sInt32)eDSCannotAccessSession );
}
else if ( ldap_result2error(outHost, result, 1) != LDAP_SUCCESS )
{
if ( (pConfig != nil) && (pConfig->fServerName != nil) )
{
LogFailedConnection("Bind failure in Replica retrieval", pConfig->fServerName, inLDAPNodeStruct->fDelayRebindTry);
}
else
{
LogFailedConnection("Bind failure in Replica retrieval", inLDAPNodeStruct->fServerName, inLDAPNodeStruct->fDelayRebindTry);
}
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
inLDAPNodeStruct->fHost = outHost;
throw( (sInt32)eDSCannotAccessSession );
}
}
inLDAPNodeStruct->fConnectionStatus = kConnectionSafe;
aRepList = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
aWriteableList = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
if ( (foundResult = GetReplicaListMessage(outHost, searchTimeout, inConfigServerString, aRepList, aWriteableList)) == eDSNoErr )
{
bMessageFound = true;
}
else if ( (foundResult = ExtractReplicaListMessage(outHost, searchTimeout, inLDAPNodeStruct, inConfigFromXML, aRepList, aWriteableList)) == eDSNoErr )
{
bMessageFound = true;
}
if (bMessageFound)
{
if (aRepList != NULL)
{
if (CFArrayGetCount(aRepList) > 0)
{
bool bHadLoopback = false;
if( inOutRepList )
{
CFRange inRangeList = CFRangeMake(0,CFArrayGetCount(inOutRepList));
if( CFArrayContainsValue(inOutRepList, inRangeList, CFSTR("127.0.0.1")) || CFArrayContainsValue(inOutRepList, inRangeList, CFSTR("localhost")) )
{
bHadLoopback = true;
}
CFArrayRemoveAllValues( inOutRepList );
CFArrayAppendArray( inOutRepList, aRepList, CFRangeMake(0,CFArrayGetCount(aRepList)));
CFRelease(aRepList);
aRepList = NULL;
}
else
{
inOutRepList = aRepList;
aRepList = NULL;
}
if( bHadLoopback )
{
CFStringRef loopStr = CFStringCreateWithCString( NULL, "127.0.0.1", kCFStringEncodingUTF8 );
CFArrayInsertValueAtIndex( inOutRepList, 0, loopStr );
CFRelease( loopStr );
}
foundResult = eDSNoErr;
}
else
{
CFRelease(aRepList);
aRepList = NULL;
}
}
if (aWriteableList != NULL)
{
if (CFArrayGetCount(aWriteableList) > 0)
{
if( inOutWriteableList )
{
CFArrayRemoveAllValues( inOutWriteableList );
CFArrayAppendArray(inOutWriteableList, aWriteableList, CFRangeMake(0,CFArrayGetCount(aWriteableList)));
CFRelease(aWriteableList);
aWriteableList = NULL;
}
else
{
inOutWriteableList = aWriteableList;
aWriteableList = NULL;
}
foundResult = eDSNoErr;
}
else
{
CFRelease(aWriteableList);
aWriteableList = NULL;
}
}
}
CFStringRef replicaStrRef = NULL;
CFIndex numReps = NULL;
if (inOutRepList != NULL)
{
numReps = CFArrayGetCount(inOutRepList);
}
if ( numReps > 0)
{
CFRange rangeOfWrites = CFRangeMake( 0, (inOutWriteableList ? CFArrayGetCount(inOutWriteableList) : 0) );
for (CFIndex indexToRep=0; indexToRep < numReps; indexToRep++ )
{
replicaStrRef = (CFStringRef)::CFArrayGetValueAtIndex( inOutRepList, indexToRep );
struct addrinfo *addrList = ResolveHostName(replicaStrRef, inPort);
sReplicaInfo* newInfo = (sReplicaInfo *)calloc(1, sizeof(sReplicaInfo));
if (indexToRep == 0)
{
aList = newInfo;
oldList = newInfo;
}
else
{
oldList->fNext = newInfo;
oldList = oldList->fNext;
}
newInfo->fAddrInfo = addrList;
newInfo->hostname = CFStringCreateCopy( kCFAllocatorDefault, replicaStrRef );
if( inOutWriteableList != nil && CFArrayContainsValue(inOutWriteableList, rangeOfWrites, replicaStrRef) )
{
newInfo->bWriteable = true;
}
}
if (aList != nil) {
FreeReplicaList( *inOutList );
*inOutList = aList;
}
}
if (inLDAPNodeStruct->fHost == nil)
{
inLDAPNodeStruct->fHost = outHost;
}
else
{
ldap_unbind(outHost);
}
}
else
{
foundResult = eDSCannotAccessSession;
}
}
catch ( sInt32 err )
{
foundResult = err;
}
if( aRepList != NULL )
{
CFRelease( aRepList );
}
if( aWriteableList != NULL )
{
CFRelease( aWriteableList );
}
if (ldapAcct != nil)
{
delete (ldapAcct);
ldapAcct = nil;
}
if (ldapPasswd != nil)
{
delete (ldapPasswd);
ldapPasswd = nil;
}
return(foundResult);
}
sInt32 CLDAPNode::GetReplicaListMessage( LDAP *inHost, int inSearchTO, char *inConfigServerString, CFMutableArrayRef outRepList, CFMutableArrayRef outWriteableList )
{
sInt32 siResult = eDSRecordNotFound;
bool bResultFound = false;
int ldapMsgId = 0;
LDAPMessage *result = nil;
int ldapReturnCode = 0;
char *attrs[2] = {"altserver",NULL};
BerElement *ber = nil;
struct berval **bValues = nil;
bool bAltServerAdded = false;
if ( (ldapMsgId = ldap_search( inHost, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0) ) == -1 )
{
bResultFound = false;
}
else
{
bResultFound = true;
struct timeval tv;
tv.tv_usec = 0;
if (inSearchTO == 0)
{
tv.tv_sec = kLDAPDefaultSearchTimeoutInSeconds;
}
else
{
tv.tv_sec = inSearchTO;
}
ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, &tv, &result);
}
if ( (bResultFound) &&
( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) )
{
if (( bValues = ldap_get_values_len (inHost, result, (char *)"altServer" )) != NULL)
{
for (int i = 0; bValues[i] != NULL; i++ )
{
if ( bValues[i] != NULL )
{
int offset = 0;
char *strPtr = bValues[i]->bv_val;
if (strlen(strPtr) >= 9) {
if (strncmp(strPtr,"ldaps://",8) == 0)
{
offset = 8;
}
if (strncmp(strPtr,"ldap://",7) == 0)
{
offset = 7;
}
}
char *strEnd = nil;
strEnd = strchr(strPtr+offset,':');
if (strEnd != nil)
{
strEnd[0] = '\0';
}
else
{
strEnd = strchr(strPtr+offset,'/');
if (strEnd != nil)
{
strEnd[0] = '\0';
}
}
CFStringRef aCFString = CFStringCreateWithCString( NULL, strPtr+offset, kCFStringEncodingMacRoman );
CFArrayAppendValue(outRepList, aCFString);
CFRelease(aCFString);
bAltServerAdded = true;
siResult = eDSNoErr;
}
}
ldap_value_free_len(bValues);
}
if (ber != nil)
{
ber_free( ber, 0 );
}
ldap_msgfree( result );
result = nil;
} else if (ldapReturnCode == LDAP_TIMEOUT)
{
siResult = eDSServerTimeout;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
else
{
siResult = eDSRecordNotFound;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
DSSearchCleanUp(inHost, ldapMsgId);
if (bAltServerAdded && (inConfigServerString != nil) )
{
CFStringRef aCFString = CFStringCreateWithCString( NULL, inConfigServerString, kCFStringEncodingMacRoman );
CFArrayInsertValueAtIndex(outRepList, 0, aCFString);
CFRelease(aCFString);
}
return( siResult );
}
sInt32 CLDAPNode::ExtractReplicaListMessage( LDAP *inHost, int inSearchTO, sLDAPNodeStruct *inLDAPNodeStruct, CLDAPv3Configs *inConfigFromXML, CFMutableArrayRef outRepList, CFMutableArrayRef outWriteableList )
{
sInt32 siResult = eDSRecordNotFound;
bool bResultFound = false;
int ldapMsgId = 0;
LDAPMessage *result = nil;
int ldapReturnCode = 0;
BerElement *ber = nil;
struct berval **bValues = nil;
char *pAttr = nil;
LDAPControl **serverctrls = nil;
LDAPControl **clientctrls = nil;
char *nativeRecType = nil;
bool bOCANDGroup = false;
CFArrayRef OCSearchList = nil;
ber_int_t scope = LDAP_SCOPE_BASE;
char *queryFilter = nil;
char *repListAttr = nil;
char *writeListAttr = nil;
int whichAttr = 0;
if (inLDAPNodeStruct == nil)
{
return(siResult);
}
nativeRecType = CLDAPv3Plugin::MapRecToLDAPType( kDSStdRecordTypeConfig,
inLDAPNodeStruct->fLDAPConfigTableIndex,
1,
&bOCANDGroup,
&OCSearchList,
&scope,
inConfigFromXML );
if (nativeRecType == nil)
{
return(eDSNoStdMappingAvailable);
}
queryFilter = CLDAPv3Plugin::BuildLDAPQueryFilter( kDSNAttrRecordName,
"ldapreplicas",
eDSExact,
inLDAPNodeStruct->fLDAPConfigTableIndex,
false,
kDSStdRecordTypeConfig,
nativeRecType,
bOCANDGroup,
OCSearchList,
inConfigFromXML );
if (OCSearchList != nil)
{
CFRelease(OCSearchList);
OCSearchList = nil;
}
if (queryFilter == nil)
{
if (nativeRecType != nil)
{
free(nativeRecType);
nativeRecType = nil;
}
return(siResult);
}
ldapReturnCode = ldap_search_ext( inHost,
nativeRecType,
scope,
queryFilter,
NULL,
0,
serverctrls,
clientctrls,
0, 0,
&ldapMsgId );
if (ldapReturnCode == LDAP_SUCCESS)
{
bResultFound = true;
struct timeval tv;
tv.tv_usec = 0;
if (inSearchTO == 0)
{
tv.tv_sec = kLDAPDefaultSearchTimeoutInSeconds;
}
else
{
tv.tv_sec = inSearchTO;
}
ldapReturnCode = ldap_result(inHost, ldapMsgId, 0, &tv, &result);
}
if (nativeRecType != nil)
{
free(nativeRecType);
nativeRecType = nil;
}
if (queryFilter != nil)
{
free(queryFilter);
queryFilter = nil;
}
if (serverctrls) ldap_controls_free( serverctrls );
if (clientctrls) ldap_controls_free( clientctrls );
if ( (bResultFound) &&
( ldapReturnCode == LDAP_RES_SEARCH_ENTRY ) )
{
siResult = eDSNoErr;
repListAttr = CLDAPv3Plugin::MapAttrToLDAPType( kDSStdRecordTypeConfig,
kDSNAttrLDAPReadReplicas,
inLDAPNodeStruct->fLDAPConfigTableIndex,
1,
inConfigFromXML );
writeListAttr = CLDAPv3Plugin::MapAttrToLDAPType( kDSStdRecordTypeConfig,
kDSNAttrLDAPWriteReplicas,
inLDAPNodeStruct->fLDAPConfigTableIndex,
1,
inConfigFromXML );
for ( pAttr = ldap_first_attribute (inHost, result, &ber );
pAttr != NULL; pAttr = ldap_next_attribute(inHost, result, ber ) )
{
whichAttr = 0;
if ( ( repListAttr != nil ) && ( strcmp(pAttr, repListAttr) == 0 ) )
{
whichAttr = 1;
}
if ( ( writeListAttr != nil ) && ( strcmp(pAttr, writeListAttr) == 0 ) )
{
whichAttr = 2;
}
if ( ( whichAttr != 0 ) && (( bValues = ldap_get_values_len (inHost, result, pAttr )) != NULL) )
{
for (int i = 0; bValues[i] != NULL; i++ )
{
if ( bValues[i] != NULL )
{
int offset = 0;
char *strPtr = bValues[i]->bv_val;
if (strlen(strPtr) >= 9) {
if (strncmp(strPtr,"ldaps://",8) == 0)
{
offset = 8;
}
if (strncmp(strPtr,"ldap://",7) == 0)
{
offset = 7;
}
}
char *strEnd = nil;
strEnd = strchr(strPtr+offset,':');
if (strEnd != nil)
{
strEnd[0] = '\0';
}
else
{
strEnd = strchr(strPtr+offset,'/');
if (strEnd != nil)
{
strEnd[0] = '\0';
}
}
if (whichAttr == 1)
{
CFStringRef aCFString = CFStringCreateWithCString( NULL, strPtr+offset, kCFStringEncodingMacRoman );
CFArrayAppendValue(outRepList, aCFString);
CFRelease(aCFString);
}
else
{
CFStringRef aCFString = CFStringCreateWithCString( NULL, strPtr+offset, kCFStringEncodingMacRoman );
CFArrayAppendValue(outWriteableList, aCFString);
CFRelease(aCFString);
}
}
}
ldap_value_free_len(bValues);
} ldap_memfree( pAttr );
}
if (ber != nil)
{
ber_free( ber, 0 );
}
ldap_msgfree( result );
result = nil;
} else if (ldapReturnCode == LDAP_TIMEOUT)
{
siResult = eDSServerTimeout;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
else
{
siResult = eDSRecordNotFound;
if ( result != nil )
{
ldap_msgfree( result );
result = nil;
}
}
DSSearchCleanUp(inHost, ldapMsgId);
if ( repListAttr != nil )
{
free(repListAttr);
repListAttr = nil;
}
if ( writeListAttr != nil )
{
free(writeListAttr);
writeListAttr = nil;
}
return( siResult );
}
void CLDAPNode::RetrieveServerMappingsIfRequired(sLDAPNodeStruct *inLDAPNodeStruct, CLDAPv3Configs *inConfigFromXML)
{
sLDAPConfigData *pConfig = nil;
if (inLDAPNodeStruct != nil)
{
pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( inLDAPNodeStruct->fLDAPConfigTableIndex );
if ( (inLDAPNodeStruct->fHost != nil) && (pConfig != nil) && (pConfig->bGetServerMappings) )
{
char **aMapSearchBase = nil;
uInt32 numberBases = 0;
if ( (pConfig->fMapSearchBase == nil) || ( strcmp(pConfig->fMapSearchBase,"") == 0 ) )
{
aMapSearchBase = GetNamingContexts( inLDAPNodeStruct->fHost, pConfig->fOpenCloseTimeout, &numberBases );
if( aMapSearchBase == (char **) -1 )
{
aMapSearchBase = nil;
LogFailedConnection("GetNamingContexts failure", pConfig->fServerName, inLDAPNodeStruct->fDelayRebindTry);
inLDAPNodeStruct->fConnectionStatus = kConnectionUnknown;
inLDAPNodeStruct->fDelayedBindTime = time( nil ) + inLDAPNodeStruct->fDelayRebindTry;
}
}
else
{
numberBases = 1;
aMapSearchBase = (char **)calloc(numberBases+1, sizeof (char *));
aMapSearchBase[0] = strdup(pConfig->fMapSearchBase);
}
for (uInt32 baseIndex = 0; (baseIndex < numberBases) && (aMapSearchBase[baseIndex] != nil); baseIndex++)
{
if (inConfigFromXML != nil)
{
if ( (inConfigFromXML->UpdateLDAPConfigWithServerMappings( pConfig->fServerName, aMapSearchBase[baseIndex], pConfig->fServerPort, pConfig->bIsSSL, pConfig->bUseAsDefaultLDAP, inLDAPNodeStruct->fHost )) == eDSNoErr )
{
pConfig->bGetServerMappings = false;
break;
}
else
{
syslog(LOG_INFO,"CLDAPNode::SafeOpen Can't retrieve server mappings from search base of <%s>.", aMapSearchBase[baseIndex] );
}
}
else
{
syslog(LOG_INFO,"CLDAPNode::SafeOpen CLDAPv3Configs pointer is nil so can't retrieve server mappings.");
break;
}
}
if (pConfig->bGetServerMappings == true)
{
syslog(LOG_INFO,"CLDAPNode::SafeOpen Cannot retrieve server mappings at this time.");
}
if (aMapSearchBase != nil)
{
for (uInt32 bIndex = 0; bIndex < numberBases; bIndex++)
{
if ( aMapSearchBase[bIndex] != nil )
{
free(aMapSearchBase[bIndex]);
aMapSearchBase[bIndex] = nil;
}
}
free(aMapSearchBase);
}
}
}
}
void CLDAPNode::FreeReplicaList( sReplicaInfo *inList )
{
while( inList != nil)
{
sReplicaInfo *nextItem = inList->fNext;
freeaddrinfo(inList->fAddrInfo);
if (inList->hostname != NULL)
{
CFRelease(inList->hostname);
}
free(inList);
inList = nextItem;
}
}
char *CLDAPNode::LDAPWithBlockingSocket( struct addrinfo *addrInfo, int seconds )
{
int aSock;
int val = 1;
int len = sizeof(val);
struct timeval recvTimeoutVal = { seconds, 0 };
char *returnHostAddress = NULL;
aSock = socket( addrInfo->ai_family, addrInfo->ai_socktype, addrInfo->ai_protocol );
if (aSock != -1)
{
setsockopt( aSock, SOL_SOCKET, SO_NOSIGPIPE, &val, len );
setsockopt( aSock, SOL_SOCKET, SO_RCVTIMEO, &recvTimeoutVal, sizeof(recvTimeoutVal) );
if( connect(aSock, addrInfo->ai_addr, addrInfo->ai_addrlen) == 0 )
{
returnHostAddress = ConvertToIPAddress( addrInfo );
}
close(aSock);
}
return returnHostAddress;
}
char *CLDAPNode::ConvertToIPAddress( struct addrinfo *addrInfo )
{
char *returnHostAddress = NULL;
if (addrInfo->ai_family == AF_INET)
{
returnHostAddress = (char *) calloc( 129, 1 );
if( inet_ntop( AF_INET, (const void *)&(((struct sockaddr_in*)(addrInfo->ai_addr))->sin_addr), returnHostAddress, 129 ) == NULL )
{
free( returnHostAddress );
returnHostAddress = NULL;
}
}
else if (addrInfo->ai_family == AF_INET6)
{
returnHostAddress = (char *) calloc( 129, 1 );
if( inet_ntop( AF_INET6, (const void *)&(((struct sockaddr_in6*)(addrInfo->ai_addr))->sin6_addr), returnHostAddress, 129 ) == NULL )
{
free( returnHostAddress );
returnHostAddress = NULL;
}
}
return returnHostAddress;
}
bool CLDAPNode::IsLocalAddress( struct addrinfo *addrInfo )
{
struct ifaddrs *ifa_list = nil, *ifa = nil;
bool bReturn = false;
if( getifaddrs(&ifa_list) != -1 )
{
for( ifa = ifa_list; ifa; ifa = ifa->ifa_next )
{
if( ifa->ifa_addr->sa_family == addrInfo->ai_addr->sa_family )
{
if( ifa->ifa_addr->sa_family == AF_INET )
{
struct sockaddr_in *interface = (struct sockaddr_in *)ifa->ifa_addr;
struct sockaddr_in *check = (struct sockaddr_in *) addrInfo->ai_addr;
if( interface->sin_addr.s_addr == check->sin_addr.s_addr )
{
bReturn = true;
break;
}
}
if( ifa->ifa_addr->sa_family == AF_INET6 )
{
struct sockaddr_in6 *interface = (struct sockaddr_in6 *)ifa->ifa_addr;
struct sockaddr_in6 *check = (struct sockaddr_in6 *)addrInfo->ai_addr;
if( memcmp( &interface->sin6_addr, &check->sin6_addr, sizeof(struct in6_addr) ) == 0 )
{
bReturn = true;
break;
}
}
}
}
freeifaddrs(ifa_list);
}
return bReturn;
}
bool CLDAPNode::ReachableAddress( struct addrinfo *addrInfo )
{
bool bReturn = IsLocalAddress( addrInfo );
if( bReturn == false )
{
bReturn = checkReachability(addrInfo->ai_addr);
}
return bReturn;
}
void CLDAPNode::CheckSASLMethods( sLDAPNodeStruct *inLDAPNodeStruct, CLDAPv3Configs *inConfigFromXML )
{
sLDAPConfigData *pConfig = nil;
if (inLDAPNodeStruct != nil )
{
pConfig = (sLDAPConfigData *)gLDAPConfigTable->GetItemData( inLDAPNodeStruct->fLDAPConfigTableIndex );
if( pConfig != nil && pConfig->fSASLmethods == NULL )
{
LDAPMessage *result = nil;
int ldapReturnCode = 0;
char *attrs[2] = { "supportedSASLMechanisms",NULL };
BerElement *ber = nil;
struct berval **bValues = nil;
char *pAttr = nil;
struct timeval tv = { 0, 0 };
pConfig->bBuildReplicaList = false;
LDAP *aHost = InitLDAPConnection( inLDAPNodeStruct, pConfig, inConfigFromXML, false );
pConfig->bBuildReplicaList = true;
DBGLOG( kLogPlugin, "CLDAPNode::Getting SASL Methods" );
if( aHost )
{
if ( pConfig->bIsSSL )
{
int ldapOptVal = LDAP_OPT_X_TLS_HARD;
ldap_set_option( aHost, LDAP_OPT_X_TLS, &ldapOptVal );
}
ldap_set_option(aHost, LDAP_OPT_REFERRALS, (pConfig->bReferrals ? LDAP_OPT_ON : LDAP_OPT_OFF) );
int version = LDAP_VERSION3;
ldap_set_option( aHost, LDAP_OPT_PROTOCOL_VERSION, &version );
int bindMsgId = ldap_simple_bind( aHost, NULL, NULL );
tv.tv_sec = (pConfig->fOpenCloseTimeout ? pConfig->fOpenCloseTimeout : kLDAPDefaultOpenCloseTimeoutInSeconds);
ldapReturnCode = ldap_result( aHost, bindMsgId, 0, &tv, &result );
if( ldapReturnCode == 0 )
{
ldap_abandon( aHost, bindMsgId );
}
else if( ldap_result2error(aHost, result, 1) == LDAP_SUCCESS )
{
tv.tv_sec = (pConfig->fSearchTimeout ? pConfig->fSearchTimeout : kLDAPDefaultOpenCloseTimeoutInSeconds);
pConfig->fSASLmethods = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
ldapReturnCode = ldap_search_ext_s( aHost,
"",
LDAP_SCOPE_BASE,
"(objectclass=*)",
attrs,
false,
NULL,
NULL,
&tv, 0,
&result );
if (ldapReturnCode == LDAP_SUCCESS)
{
pAttr = ldap_first_attribute (aHost, result, &ber );
if (pAttr != nil)
{
if( (bValues = ldap_get_values_len (aHost, result, pAttr)) != NULL )
{
uInt32 ii = 0;
while( bValues[ii] != NULL )
{
CFStringRef value = CFStringCreateWithCString( NULL, bValues[ii]->bv_val, kCFStringEncodingUTF8 );
CFArrayAppendValue( pConfig->fSASLmethods, value );
CFRelease( value );
ii++;
}
ldap_value_free_len( bValues );
} ldap_memfree( pAttr );
}
if (ber != nil)
{
ber_free( ber, 0 );
}
ldap_msgfree( result );
result = nil;
DBGLOG( kLogPlugin, "CLDAPNode::Successful SASL Method retrieval" );
}
}
ldap_unbind_ext( aHost, NULL, NULL );
inLDAPNodeStruct->fHost = NULL;
}
}
}
}
bool CLDAPNode::LocalServerIsLDAPReplica( )
{
bool bResult = false;
char* fileContents = NULL;
try
{
CFile slapdConf("/etc/openldap/slapd.conf");
CFile slapdMacOSXConf;
fileContents = (char*)calloc( 1, slapdConf.FileSize() + 1 );
if ( fileContents != NULL )
{
slapdConf.Read( fileContents, slapdConf.FileSize() );
if ((strncmp( fileContents, "updatedn", sizeof("updatedn") ) == 0)
|| (strstr( fileContents, "\nupdatedn" ) != 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, slapdConf.FileSize() );
if ((strncmp( fileContents, "updatedn", sizeof("updatedn") ) == 0)
|| (strstr( fileContents, "\nupdatedn" ) != NULL))
{
bResult = true;
}
free( fileContents );
fileContents = NULL;
}
}
catch ( ... )
{
}
if (fileContents != NULL)
{
free( fileContents );
}
return bResult;
}
void CLDAPNode::EnsureCheckFailedConnectionsThreadIsRunning( void )
{
if( fCheckThreadActive == false )
{
fCheckThreadActive = true;
pthread_t checkThread;
pthread_attr_t _DefaultAttrs;
::pthread_attr_init( &_DefaultAttrs );
::pthread_attr_setdetachstate( &_DefaultAttrs, PTHREAD_CREATE_DETACHED);
pthread_create( &checkThread, &_DefaultAttrs, checkFailedServers, (void *)this );
}
}