1368 lines
36 KiB
C++
1368 lines
36 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows NT Security
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1999
|
|
//
|
|
// File: ldapsp.cpp
|
|
//
|
|
// Contents: LDAP Scheme Provider for Remote Object Retrieval
|
|
//
|
|
// History: 23-Jul-97 kirtd Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
#include <global.hxx>
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapRetrieveEncodedObject
|
|
//
|
|
// Synopsis: retrieve encoded object via LDAP protocol
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI LdapRetrieveEncodedObject (
|
|
IN LPCSTR pszUrl,
|
|
IN LPCSTR pszObjectOid,
|
|
IN DWORD dwRetrievalFlags,
|
|
IN DWORD dwTimeout,
|
|
OUT PCRYPT_BLOB_ARRAY pObject,
|
|
OUT PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
|
|
OUT LPVOID* ppvFreeContext,
|
|
IN HCRYPTASYNC hAsyncRetrieve,
|
|
IN PCRYPT_CREDENTIALS pCredentials,
|
|
IN PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
IObjectRetriever* por = NULL;
|
|
|
|
if ( !( dwRetrievalFlags & CRYPT_ASYNC_RETRIEVAL ) )
|
|
{
|
|
por = new CLdapSynchronousRetriever;
|
|
}
|
|
|
|
if ( por == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
fResult = por->RetrieveObjectByUrl(
|
|
pszUrl,
|
|
pszObjectOid,
|
|
dwRetrievalFlags,
|
|
dwTimeout,
|
|
(LPVOID *)pObject,
|
|
ppfnFreeObject,
|
|
ppvFreeContext,
|
|
hAsyncRetrieve,
|
|
pCredentials,
|
|
NULL,
|
|
pAuxInfo
|
|
);
|
|
|
|
por->Release();
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapFreeEncodedObject
|
|
//
|
|
// Synopsis: free encoded object retrieved via LdapRetrieveEncodedObject
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID WINAPI LdapFreeEncodedObject (
|
|
IN LPCSTR pszObjectOid,
|
|
IN PCRYPT_BLOB_ARRAY pObject,
|
|
IN LPVOID pvFreeContext
|
|
)
|
|
{
|
|
assert( pvFreeContext == NULL );
|
|
|
|
LdapFreeCryptBlobArray( pObject );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapCancelAsyncRetrieval
|
|
//
|
|
// Synopsis: cancel asynchronous object retrieval
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL WINAPI LdapCancelAsyncRetrieval (
|
|
IN HCRYPTASYNC hAsyncRetrieve
|
|
)
|
|
{
|
|
SetLastError( (DWORD) E_NOTIMPL );
|
|
return( FALSE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLdapSynchronousRetriever::CLdapSynchronousRetriever, public
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CLdapSynchronousRetriever::CLdapSynchronousRetriever ()
|
|
{
|
|
m_cRefs = 1;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLdapSynchronousRetriever::~CLdapSynchronousRetriever, public
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CLdapSynchronousRetriever::~CLdapSynchronousRetriever ()
|
|
{
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLdapSynchronousRetriever::AddRef, public
|
|
//
|
|
// Synopsis: IRefCountedObject::AddRef
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
CLdapSynchronousRetriever::AddRef ()
|
|
{
|
|
InterlockedIncrement( (LONG *)&m_cRefs );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLdapSynchronousRetriever::Release, public
|
|
//
|
|
// Synopsis: IRefCountedObject::Release
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
CLdapSynchronousRetriever::Release ()
|
|
{
|
|
if ( InterlockedDecrement( (LONG *)&m_cRefs ) == 0 )
|
|
{
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLdapSynchronousRetriever::RetrieveObjectByUrl, public
|
|
//
|
|
// Synopsis: IObjectRetriever::RetrieveObjectByUrl
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CLdapSynchronousRetriever::RetrieveObjectByUrl (
|
|
LPCSTR pszUrl,
|
|
LPCSTR pszObjectOid,
|
|
DWORD dwRetrievalFlags,
|
|
DWORD dwTimeout,
|
|
LPVOID* ppvObject,
|
|
PFN_FREE_ENCODED_OBJECT_FUNC* ppfnFreeObject,
|
|
LPVOID* ppvFreeContext,
|
|
HCRYPTASYNC hAsyncRetrieve,
|
|
PCRYPT_CREDENTIALS pCredentials,
|
|
LPVOID pvVerify,
|
|
PCRYPT_RETRIEVE_AUX_INFO pAuxInfo
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD LastError = 0;
|
|
LDAP_URL_COMPONENTS LdapUrlComponents;
|
|
LDAP* pld = NULL;
|
|
BOOL fLdapUrlCracked = FALSE;
|
|
|
|
assert( hAsyncRetrieve == NULL );
|
|
|
|
if ( dwRetrievalFlags & CRYPT_CACHE_ONLY_RETRIEVAL )
|
|
{
|
|
return( SchemeRetrieveCachedCryptBlobArray(
|
|
pszUrl,
|
|
dwRetrievalFlags,
|
|
(PCRYPT_BLOB_ARRAY)ppvObject,
|
|
ppfnFreeObject,
|
|
ppvFreeContext,
|
|
pAuxInfo
|
|
) );
|
|
}
|
|
|
|
fResult = LdapCrackUrl( pszUrl, &LdapUrlComponents );
|
|
|
|
#if DBG
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
LdapDisplayUrlComponents( &LdapUrlComponents );
|
|
}
|
|
|
|
#endif
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fLdapUrlCracked = TRUE;
|
|
|
|
if ( dwRetrievalFlags & CRYPT_LDAP_SCOPE_BASE_ONLY_RETRIEVAL )
|
|
{
|
|
if ( LdapUrlComponents.Scope != LDAP_SCOPE_BASE )
|
|
{
|
|
fResult = FALSE;
|
|
SetLastError( (DWORD) E_INVALIDARG );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
DWORD iAuth;
|
|
|
|
if ( dwRetrievalFlags &
|
|
(CRYPT_LDAP_AREC_EXCLUSIVE_RETRIEVAL |
|
|
CRYPT_LDAP_SIGN_RETRIEVAL) )
|
|
{
|
|
// Only attempt AUTH_SSPI binds
|
|
iAuth = 1;
|
|
}
|
|
else
|
|
{
|
|
// First attempt AUTH_SIMPLE bind. If that fails or returns
|
|
// nothing, then, attempt AUTH_SSPI bind.
|
|
iAuth = 0;
|
|
}
|
|
|
|
for ( ; iAuth < 2; iAuth++)
|
|
{
|
|
fResult = LdapGetBindings(
|
|
LdapUrlComponents.pszHost,
|
|
LdapUrlComponents.Port,
|
|
dwRetrievalFlags,
|
|
0 == iAuth ? LDAP_BIND_AUTH_SIMPLE_ENABLE_FLAG :
|
|
LDAP_BIND_AUTH_SSPI_ENABLE_FLAG,
|
|
dwTimeout,
|
|
pCredentials,
|
|
&pld
|
|
);
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = LdapSendReceiveUrlRequest(
|
|
pld,
|
|
&LdapUrlComponents,
|
|
dwRetrievalFlags,
|
|
dwTimeout,
|
|
(PCRYPT_BLOB_ARRAY)ppvObject
|
|
);
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
LastError = GetLastError();
|
|
LdapFreeBindings( pld );
|
|
pld = NULL;
|
|
SetLastError( LastError );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
if ( !( dwRetrievalFlags & CRYPT_DONT_CACHE_RESULT ) )
|
|
{
|
|
fResult = SchemeCacheCryptBlobArray(
|
|
pszUrl,
|
|
dwRetrievalFlags,
|
|
(PCRYPT_BLOB_ARRAY)ppvObject,
|
|
pAuxInfo
|
|
);
|
|
|
|
if ( fResult == FALSE )
|
|
{
|
|
LdapFreeEncodedObject(
|
|
pszObjectOid,
|
|
(PCRYPT_BLOB_ARRAY)ppvObject,
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SchemeRetrieveUncachedAuxInfo( pAuxInfo );
|
|
}
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
*ppfnFreeObject = LdapFreeEncodedObject;
|
|
*ppvFreeContext = NULL;
|
|
}
|
|
else
|
|
{
|
|
LastError = GetLastError();
|
|
}
|
|
|
|
if ( fLdapUrlCracked == TRUE )
|
|
{
|
|
LdapFreeUrlComponents( &LdapUrlComponents );
|
|
}
|
|
|
|
LdapFreeBindings( pld );
|
|
|
|
SetLastError( LastError );
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CLdapSynchronousRetriever::CancelAsyncRetrieval, public
|
|
//
|
|
// Synopsis: IObjectRetriever::CancelAsyncRetrieval
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
CLdapSynchronousRetriever::CancelAsyncRetrieval ()
|
|
{
|
|
SetLastError( (DWORD) E_NOTIMPL );
|
|
return( FALSE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapCrackUrl
|
|
//
|
|
// Synopsis: Crack an LDAP URL into its relevant parts. The result must
|
|
// be freed using LdapFreeUrlComponents
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapCrackUrl (
|
|
LPCSTR pszUrl,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
ULONG cbUrl = INTERNET_MAX_PATH_LENGTH;
|
|
LPSTR pszHostInfo = NULL;
|
|
LPSTR pszDN = NULL;
|
|
LPSTR pszAttrList = NULL;
|
|
LPSTR pszScope = NULL;
|
|
LPSTR pszFilter = NULL;
|
|
LPSTR pszToken = NULL;
|
|
CHAR psz[INTERNET_MAX_PATH_LENGTH+1];
|
|
|
|
//
|
|
// Capture the URL and initialize the out parameter
|
|
//
|
|
|
|
__try
|
|
{
|
|
if ( InternetCanonicalizeUrlA(
|
|
pszUrl,
|
|
psz,
|
|
&cbUrl,
|
|
ICU_NO_ENCODE | ICU_DECODE
|
|
) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastError( GetExceptionCode() );
|
|
return( FALSE );
|
|
}
|
|
|
|
memset( pLdapUrlComponents, 0, sizeof( LDAP_URL_COMPONENTS ) );
|
|
|
|
//
|
|
// Find the host
|
|
//
|
|
|
|
pszHostInfo = psz + sizeof( "ldap://" ) - sizeof( CHAR );
|
|
if ( *pszHostInfo == '/' )
|
|
{
|
|
pszToken = pszHostInfo + 1;
|
|
pszHostInfo = NULL;
|
|
}
|
|
else
|
|
{
|
|
#if 0
|
|
pszHostInfo = strtok( pszHostInfo, "/" );
|
|
#else
|
|
pszToken = pszHostInfo;
|
|
while ( ( *pszToken != '\0' ) && ( *pszToken != '/' ) )
|
|
pszToken++;
|
|
|
|
if ( *pszToken == '/' )
|
|
{
|
|
*pszToken = '\0';
|
|
pszToken += 1;
|
|
}
|
|
|
|
while ( *pszToken == '/' )
|
|
pszToken++;
|
|
#endif
|
|
|
|
}
|
|
|
|
//
|
|
// Find the DN
|
|
//
|
|
|
|
if ( pszToken != NULL )
|
|
{
|
|
pszDN = "";
|
|
|
|
if ( *pszToken != '\0' )
|
|
{
|
|
if ( *pszToken == '?' )
|
|
{
|
|
pszToken += 1;
|
|
}
|
|
else
|
|
{
|
|
pszDN = pszToken;
|
|
|
|
do
|
|
{
|
|
pszToken += 1;
|
|
}
|
|
while ( ( *pszToken != '\0' ) && ( *pszToken != '?' ) );
|
|
|
|
if ( *pszToken == '?' )
|
|
{
|
|
*pszToken = '\0';
|
|
pszToken += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszDN = strtok( pszToken, "?" );
|
|
pszToken = NULL;
|
|
if ( pszDN == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_INVALIDARG );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for attributes
|
|
//
|
|
|
|
if ( pszToken != NULL )
|
|
{
|
|
if ( *pszToken == '?' )
|
|
{
|
|
pszAttrList = "";
|
|
pszToken += 1;
|
|
}
|
|
else if ( *pszToken == '\0' )
|
|
{
|
|
pszAttrList = NULL;
|
|
}
|
|
else
|
|
{
|
|
pszAttrList = strtok( pszToken, "?" );
|
|
pszToken = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pszAttrList = strtok( NULL, "?" );
|
|
}
|
|
|
|
//
|
|
// Check for a scope and filter
|
|
//
|
|
|
|
if ( pszAttrList != NULL )
|
|
{
|
|
pszScope = strtok( pszToken, "?" );
|
|
if ( pszScope != NULL )
|
|
{
|
|
pszFilter = strtok( NULL, "?" );
|
|
}
|
|
}
|
|
|
|
if ( pszScope == NULL )
|
|
{
|
|
pszScope = "base";
|
|
}
|
|
|
|
if ( pszFilter == NULL )
|
|
{
|
|
pszFilter = "(objectClass=*)";
|
|
}
|
|
|
|
//
|
|
// Now we build up our URL components
|
|
//
|
|
|
|
fResult = LdapParseCrackedHost( pszHostInfo, pLdapUrlComponents );
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = LdapParseCrackedDN( pszDN, pLdapUrlComponents );
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = LdapParseCrackedAttributeList(
|
|
pszAttrList,
|
|
pLdapUrlComponents
|
|
);
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = LdapParseCrackedScopeAndFilter(
|
|
pszScope,
|
|
pszFilter,
|
|
pLdapUrlComponents
|
|
);
|
|
}
|
|
|
|
if ( fResult != TRUE )
|
|
{
|
|
LdapFreeUrlComponents( pLdapUrlComponents );
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedHost
|
|
//
|
|
// Synopsis: Parse the cracked host string (pszHost is modified)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedHost (
|
|
LPSTR pszHost,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
LPSTR pszPort;
|
|
|
|
if ( pszHost == NULL )
|
|
{
|
|
pLdapUrlComponents->pszHost = NULL;
|
|
pLdapUrlComponents->Port = LDAP_PORT;
|
|
return( TRUE );
|
|
}
|
|
|
|
pszPort = strchr( pszHost, ':' );
|
|
if ( pszPort != NULL )
|
|
{
|
|
*pszPort = '\0';
|
|
pszPort++;
|
|
}
|
|
|
|
pLdapUrlComponents->pszHost = new CHAR [strlen( pszHost ) + 1];
|
|
if ( pLdapUrlComponents->pszHost == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
strcpy( pLdapUrlComponents->pszHost, pszHost );
|
|
pLdapUrlComponents->Port = 0;
|
|
|
|
if ( pszPort != NULL )
|
|
{
|
|
pLdapUrlComponents->Port = atol( pszPort );
|
|
}
|
|
|
|
if ( pLdapUrlComponents->Port == 0 )
|
|
{
|
|
pLdapUrlComponents->Port = LDAP_PORT;
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedDN
|
|
//
|
|
// Synopsis: Parse the cracked DN
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedDN (
|
|
LPSTR pszDN,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
pLdapUrlComponents->pszDN = new CHAR [strlen( pszDN ) + 1];
|
|
if ( pLdapUrlComponents->pszDN == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
strcpy( pLdapUrlComponents->pszDN, pszDN );
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedAttributeList
|
|
//
|
|
// Synopsis: Parse the cracked attribute list
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedAttributeList (
|
|
LPSTR pszAttrList,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
LPSTR psz;
|
|
LPSTR pszAttr;
|
|
ULONG cAttr = 0;
|
|
ULONG cCount;
|
|
|
|
if ( ( pszAttrList == NULL ) || ( strlen( pszAttrList ) == 0 ) )
|
|
{
|
|
pLdapUrlComponents->cAttr = 0;
|
|
pLdapUrlComponents->apszAttr = NULL;
|
|
return( TRUE );
|
|
}
|
|
|
|
psz = new CHAR [strlen( pszAttrList ) + 1];
|
|
if ( psz == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
strcpy( psz, pszAttrList );
|
|
|
|
pszAttr = strtok( psz, "," );
|
|
while ( pszAttr != NULL )
|
|
{
|
|
cAttr += 1;
|
|
pszAttr = strtok( NULL, "," );
|
|
}
|
|
|
|
pLdapUrlComponents->apszAttr = new LPSTR [cAttr+1];
|
|
if ( pLdapUrlComponents->apszAttr == NULL )
|
|
{
|
|
delete psz;
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
pLdapUrlComponents->cAttr = cAttr;
|
|
for ( cCount = 0; cCount < cAttr; cCount++ )
|
|
{
|
|
pLdapUrlComponents->apszAttr[cCount] = psz;
|
|
psz += ( strlen(psz) + 1 );
|
|
}
|
|
|
|
pLdapUrlComponents->apszAttr[cAttr] = NULL;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedScopeAndFilter
|
|
//
|
|
// Synopsis: Parse the cracked scope and filter
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedScopeAndFilter (
|
|
LPSTR pszScope,
|
|
LPSTR pszFilter,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
ULONG Scope;
|
|
|
|
if ( _stricmp( pszScope, "base" ) == 0 )
|
|
{
|
|
Scope = LDAP_SCOPE_BASE;
|
|
}
|
|
else if ( _stricmp( pszScope, "one" ) == 0 )
|
|
{
|
|
Scope = LDAP_SCOPE_ONELEVEL;
|
|
}
|
|
else if ( _stricmp( pszScope, "sub" ) == 0 )
|
|
{
|
|
Scope = LDAP_SCOPE_SUBTREE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( (DWORD) E_INVALIDARG );
|
|
return( FALSE );
|
|
}
|
|
|
|
pLdapUrlComponents->pszFilter = new CHAR [strlen( pszFilter ) + 1];
|
|
if ( pLdapUrlComponents->pszFilter == NULL )
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
strcpy( pLdapUrlComponents->pszFilter, pszFilter );
|
|
pLdapUrlComponents->Scope = Scope;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapFreeUrlComponents
|
|
//
|
|
// Synopsis: Frees allocate URL components returned from LdapCrackUrl
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
LdapFreeUrlComponents (
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
delete pLdapUrlComponents->pszHost;
|
|
delete pLdapUrlComponents->pszDN;
|
|
|
|
if ( pLdapUrlComponents->apszAttr != NULL )
|
|
{
|
|
delete pLdapUrlComponents->apszAttr[0];
|
|
}
|
|
|
|
delete pLdapUrlComponents->apszAttr;
|
|
delete pLdapUrlComponents->pszFilter;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapGetBindings
|
|
//
|
|
// Synopsis: allocates and initializes the LDAP session binding
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapGetBindings (
|
|
LPSTR pszHost,
|
|
ULONG Port,
|
|
DWORD dwRetrievalFlags,
|
|
DWORD dwBindFlags,
|
|
DWORD dwTimeout, // milliseconds
|
|
PCRYPT_CREDENTIALS pCredentials,
|
|
LDAP** ppld
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
DWORD LastError = 0;
|
|
CRYPT_PASSWORD_CREDENTIALSA PasswordCredentials;
|
|
LDAP* pld = NULL;
|
|
BOOL fFreeCredentials = FALSE;
|
|
|
|
memset( &PasswordCredentials, 0, sizeof( PasswordCredentials ) );
|
|
PasswordCredentials.cbSize = sizeof( PasswordCredentials );
|
|
|
|
if ( SchemeGetPasswordCredentialsA(
|
|
pCredentials,
|
|
&PasswordCredentials,
|
|
&fFreeCredentials
|
|
) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pld = ldap_initA( pszHost, Port );
|
|
if ( pld != NULL )
|
|
{
|
|
SEC_WINNT_AUTH_IDENTITY_A AuthIdentity;
|
|
ULONG ldaperr;
|
|
struct l_timeval tv;
|
|
struct l_timeval *ptv = NULL;
|
|
|
|
if (dwRetrievalFlags & CRYPT_LDAP_AREC_EXCLUSIVE_RETRIEVAL)
|
|
{
|
|
void *pvOn;
|
|
pvOn = LDAP_OPT_ON;
|
|
ldap_set_option(
|
|
pld,
|
|
LDAP_OPT_AREC_EXCLUSIVE,
|
|
&pvOn
|
|
);
|
|
}
|
|
|
|
// Note, dwTimeout is in units of milliseconds.
|
|
// LDAP_OPT_TIMELIMIT is in units of seconds.
|
|
if ( 0 != dwTimeout )
|
|
{
|
|
DWORD dwTimeoutSeconds = dwTimeout / 1000;
|
|
|
|
if ( LDAP_MIN_TIMEOUT_SECONDS > dwTimeoutSeconds )
|
|
{
|
|
dwTimeoutSeconds = LDAP_MIN_TIMEOUT_SECONDS;
|
|
}
|
|
|
|
tv.tv_sec = dwTimeoutSeconds;
|
|
tv.tv_usec = 0;
|
|
ptv = &tv;
|
|
|
|
ldap_set_option( pld, LDAP_OPT_TIMELIMIT,
|
|
(void *)&dwTimeoutSeconds );
|
|
}
|
|
|
|
ldaperr = ldap_connect( pld, ptv );
|
|
|
|
if ( ( ldaperr != LDAP_SUCCESS ) && ( pszHost == NULL ) )
|
|
{
|
|
DWORD dwFlags = DS_FORCE_REDISCOVERY;
|
|
ULONG ldapsaveerr = ldaperr;
|
|
|
|
ldaperr = ldap_set_option(
|
|
pld,
|
|
LDAP_OPT_GETDSNAME_FLAGS,
|
|
(LPVOID)&dwFlags
|
|
);
|
|
|
|
if ( ldaperr == LDAP_SUCCESS )
|
|
{
|
|
ldaperr = ldap_connect( pld, ptv );
|
|
|
|
}
|
|
else
|
|
{
|
|
ldaperr = ldapsaveerr;
|
|
}
|
|
}
|
|
|
|
if ( ldaperr != LDAP_SUCCESS )
|
|
{
|
|
fResult = FALSE;
|
|
SetLastError( LdapMapErrorToWin32( ldaperr ) );
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
LPSTR pRestore;
|
|
|
|
SchemeGetAuthIdentityFromPasswordCredentialsA(
|
|
&PasswordCredentials,
|
|
&AuthIdentity,
|
|
&pRestore
|
|
);
|
|
|
|
#if DBG
|
|
printf(
|
|
"Credentials = %s\\%s <%s>\n",
|
|
AuthIdentity.Domain,
|
|
AuthIdentity.User,
|
|
AuthIdentity.Password
|
|
);
|
|
#endif
|
|
|
|
fResult = LdapSSPIOrSimpleBind(
|
|
pld,
|
|
&AuthIdentity,
|
|
dwRetrievalFlags,
|
|
dwBindFlags
|
|
);
|
|
|
|
// following doesn't globber LastError
|
|
SchemeRestorePasswordCredentialsFromAuthIdentityA(
|
|
&PasswordCredentials,
|
|
&AuthIdentity,
|
|
pRestore
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fResult = FALSE;
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
*ppld = pld;
|
|
}
|
|
else
|
|
{
|
|
LastError = GetLastError();
|
|
LdapFreeBindings( pld );
|
|
}
|
|
|
|
if ( fFreeCredentials == TRUE )
|
|
{
|
|
SchemeFreePasswordCredentialsA( &PasswordCredentials );
|
|
}
|
|
|
|
SetLastError( LastError );
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapFreeBindings
|
|
//
|
|
// Synopsis: frees allocated LDAP session binding
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
LdapFreeBindings (
|
|
LDAP* pld
|
|
)
|
|
{
|
|
if ( pld != NULL )
|
|
{
|
|
ldap_unbind_s( pld );
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapSendReceiveUrlRequest
|
|
//
|
|
// Synopsis: sends an URL based search request to the LDAP server, receives
|
|
// the result message and converts it to a CRYPT_BLOB_ARRAY of
|
|
// encoded object bits
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapSendReceiveUrlRequest (
|
|
LDAP* pld,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents,
|
|
DWORD dwRetrievalFlags,
|
|
DWORD dwTimeout, // milliseconds
|
|
PCRYPT_BLOB_ARRAY pcba
|
|
)
|
|
{
|
|
BOOL fResult;
|
|
DWORD LastError = 0;
|
|
ULONG lderr;
|
|
LDAPMessage* plm = NULL;
|
|
|
|
if ( 0 != dwTimeout )
|
|
{
|
|
DWORD dwTimeoutSeconds = dwTimeout / 1000;
|
|
struct l_timeval tv;
|
|
|
|
if ( LDAP_MIN_TIMEOUT_SECONDS > dwTimeoutSeconds )
|
|
{
|
|
dwTimeoutSeconds = LDAP_MIN_TIMEOUT_SECONDS;
|
|
}
|
|
|
|
tv.tv_sec = dwTimeoutSeconds;
|
|
tv.tv_usec = 0;
|
|
|
|
lderr = ldap_search_st(
|
|
pld,
|
|
pLdapUrlComponents->pszDN,
|
|
pLdapUrlComponents->Scope,
|
|
pLdapUrlComponents->pszFilter,
|
|
pLdapUrlComponents->apszAttr,
|
|
FALSE,
|
|
&tv,
|
|
&plm
|
|
);
|
|
}
|
|
else
|
|
{
|
|
lderr = ldap_search_s(
|
|
pld,
|
|
pLdapUrlComponents->pszDN,
|
|
pLdapUrlComponents->Scope,
|
|
pLdapUrlComponents->pszFilter,
|
|
pLdapUrlComponents->apszAttr,
|
|
FALSE,
|
|
&plm
|
|
);
|
|
}
|
|
|
|
if ( lderr != LDAP_SUCCESS )
|
|
{
|
|
if ( plm != NULL )
|
|
{
|
|
ldap_msgfree( plm );
|
|
}
|
|
|
|
SetLastError( LdapMapErrorToWin32( lderr ) );
|
|
return( FALSE );
|
|
}
|
|
|
|
fResult = LdapConvertLdapResultMessage( pld, plm, dwRetrievalFlags, pcba );
|
|
if ( !fResult )
|
|
{
|
|
LastError = GetLastError();
|
|
}
|
|
ldap_msgfree( plm );
|
|
|
|
SetLastError( LastError );
|
|
return( fResult );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapConvertResultMessage
|
|
//
|
|
// Synopsis: convert returned LDAP message to a crypt blob array
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapConvertLdapResultMessage (
|
|
LDAP* pld,
|
|
PLDAPMessage plm,
|
|
DWORD dwRetrievalFlags,
|
|
PCRYPT_BLOB_ARRAY pcba
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
PLDAPMessage plmElem;
|
|
BerElement* pber;
|
|
CHAR* pszAttr;
|
|
struct berval** apbv;
|
|
ULONG cCount;
|
|
CCryptBlobArray cba( 10, 5, fResult );
|
|
DWORD dwIndex;
|
|
ULONG cbIndex = 0;
|
|
char szIndex[33];
|
|
|
|
for ( plmElem = ldap_first_entry( pld, plm ), dwIndex = 0;
|
|
( plmElem != NULL ) && ( fResult == TRUE );
|
|
plmElem = ldap_next_entry( pld, plmElem ), dwIndex++ )
|
|
{
|
|
if ( dwRetrievalFlags & CRYPT_LDAP_INSERT_ENTRY_ATTRIBUTE )
|
|
{
|
|
_ltoa(dwIndex, szIndex, 10);
|
|
cbIndex = strlen(szIndex) + 1;
|
|
}
|
|
|
|
for ( pszAttr = ldap_first_attributeA( pld, plmElem, &pber );
|
|
( pszAttr != NULL ) && ( fResult == TRUE );
|
|
pszAttr = ldap_next_attributeA( pld, plmElem, pber ) )
|
|
{
|
|
apbv = ldap_get_values_lenA( pld, plmElem, pszAttr );
|
|
if ( apbv == NULL )
|
|
{
|
|
fResult = FALSE;
|
|
}
|
|
|
|
for ( cCount = 0;
|
|
( fResult == TRUE ) && ( apbv[cCount] != NULL );
|
|
cCount++ )
|
|
{
|
|
ULONG cbAttr = 0;
|
|
ULONG cbVal;
|
|
ULONG cbToAdd;
|
|
LPBYTE pbToAdd;
|
|
|
|
cbToAdd = cbVal = apbv[cCount]->bv_len;
|
|
|
|
if ( dwRetrievalFlags & CRYPT_LDAP_INSERT_ENTRY_ATTRIBUTE )
|
|
{
|
|
cbAttr = strlen(pszAttr) + 1;
|
|
cbToAdd += cbIndex + cbAttr;
|
|
}
|
|
|
|
pbToAdd = cba.AllocBlob( cbToAdd );
|
|
if ( pbToAdd != NULL )
|
|
{
|
|
LPBYTE pb;
|
|
|
|
pb = pbToAdd;
|
|
if ( dwRetrievalFlags & CRYPT_LDAP_INSERT_ENTRY_ATTRIBUTE )
|
|
{
|
|
memcpy( pb, szIndex, cbIndex );
|
|
pb += cbIndex;
|
|
memcpy( pb, pszAttr, cbAttr );
|
|
pb += cbAttr;
|
|
}
|
|
memcpy( pb, (LPBYTE)apbv[cCount]->bv_val, cbVal );
|
|
}
|
|
else
|
|
{
|
|
SetLastError( (DWORD) E_OUTOFMEMORY );
|
|
fResult = FALSE;
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = cba.AddBlob(
|
|
cbToAdd,
|
|
pbToAdd,
|
|
FALSE
|
|
);
|
|
if ( fResult == FALSE )
|
|
{
|
|
cba.FreeBlob( pbToAdd );
|
|
}
|
|
}
|
|
}
|
|
|
|
ldap_value_free_len( apbv );
|
|
}
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
if ( cba.GetBlobCount() > 0 )
|
|
{
|
|
cba.GetArrayInNativeForm( pcba );
|
|
}
|
|
else
|
|
{
|
|
cba.FreeArray( TRUE );
|
|
SetLastError( (DWORD) CRYPT_E_NOT_FOUND );
|
|
fResult = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cba.FreeArray( TRUE );
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapFreeCryptBlobArray
|
|
//
|
|
// Synopsis: free CRYPT_BLOB_ARRAY allocated in LdapConvertLdapResultMessage
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
LdapFreeCryptBlobArray (
|
|
PCRYPT_BLOB_ARRAY pcba
|
|
)
|
|
{
|
|
CCryptBlobArray cba( pcba, 0 );
|
|
|
|
cba.FreeArray( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapHasWriteAccess
|
|
//
|
|
// Synopsis: check if the caller has write access to the given LDAP URL
|
|
// query components
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapHasWriteAccess (
|
|
LDAP* pld,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents,
|
|
DWORD dwTimeout
|
|
)
|
|
{
|
|
BOOL fResult = FALSE;
|
|
LPSTR pszAttr = "allowedAttributesEffective";
|
|
LPSTR apszAttr[2] = {pszAttr, NULL};
|
|
LDAP_URL_COMPONENTS LdapUrlComponents;
|
|
CRYPT_BLOB_ARRAY cba;
|
|
ULONG cCount;
|
|
ULONG cbAttr;
|
|
|
|
if ( ( pLdapUrlComponents->cAttr != 1 ) ||
|
|
( pLdapUrlComponents->Scope != LDAP_SCOPE_BASE ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
memset( &LdapUrlComponents, 0, sizeof( LdapUrlComponents ) );
|
|
|
|
LdapUrlComponents.pszHost = pLdapUrlComponents->pszHost;
|
|
LdapUrlComponents.Port = pLdapUrlComponents->Port;
|
|
LdapUrlComponents.pszDN = pLdapUrlComponents->pszDN;
|
|
|
|
LdapUrlComponents.cAttr = 1;
|
|
LdapUrlComponents.apszAttr = apszAttr;
|
|
|
|
LdapUrlComponents.Scope = LDAP_SCOPE_BASE;
|
|
LdapUrlComponents.pszFilter = "(objectClass=*)";
|
|
|
|
if ( LdapSendReceiveUrlRequest( pld, &LdapUrlComponents, 0, dwTimeout, &cba ) == FALSE )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
cbAttr = strlen( pLdapUrlComponents->apszAttr[ 0 ] );
|
|
|
|
for ( cCount = 0; cCount < cba.cBlob; cCount++ )
|
|
{
|
|
if ( cba.rgBlob[ cCount ].cbData != cbAttr )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ( _strnicmp(
|
|
pLdapUrlComponents->apszAttr[ 0 ],
|
|
(LPSTR)cba.rgBlob[ cCount ].pbData,
|
|
cbAttr
|
|
) == 0 )
|
|
{
|
|
fResult = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
LdapFreeCryptBlobArray( &cba );
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapSSPIOrSimpleBind
|
|
//
|
|
// Synopsis: do a SSPI and/or simple bind
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapSSPIOrSimpleBind (
|
|
LDAP* pld,
|
|
SEC_WINNT_AUTH_IDENTITY_A* pAuthIdentity,
|
|
DWORD dwRetrievalFlags,
|
|
DWORD dwBindFlags
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
ULONG ldaperr;
|
|
ULONG uVersion= LDAP_VERSION3;
|
|
|
|
// Per bug 25497, do V3 negotiate instead of the default V2.
|
|
ldap_set_option(pld, LDAP_OPT_VERSION, &uVersion);
|
|
|
|
if (dwRetrievalFlags & CRYPT_LDAP_SIGN_RETRIEVAL)
|
|
{
|
|
void *pvOn;
|
|
pvOn = LDAP_OPT_ON;
|
|
|
|
ldaperr = ldap_set_option(
|
|
pld,
|
|
LDAP_OPT_SIGN,
|
|
&pvOn
|
|
);
|
|
if ( ldaperr != LDAP_SUCCESS )
|
|
{
|
|
SetLastError( LdapMapErrorToWin32( ldaperr ) );
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
ldaperr = LDAP_AUTH_METHOD_NOT_SUPPORTED;
|
|
|
|
if (dwBindFlags & LDAP_BIND_AUTH_SSPI_ENABLE_FLAG)
|
|
{
|
|
|
|
ldaperr = ldap_bind_sA(
|
|
pld,
|
|
NULL,
|
|
(PCHAR)pAuthIdentity,
|
|
LDAP_AUTH_SSPI
|
|
);
|
|
}
|
|
|
|
if (dwBindFlags & LDAP_BIND_AUTH_SIMPLE_ENABLE_FLAG)
|
|
{
|
|
// Per Anoop's 4/25/00 email:
|
|
// You should fall back to anonymous bind only if the server returns
|
|
// LDAP_AUTH_METHOD_NOT_SUPPORTED.
|
|
//
|
|
// Per sergiod/trevorf 4/25/01 also need to check for invalid creds
|
|
// because target server could be in a different forest.
|
|
|
|
if ( ldaperr == LDAP_AUTH_METHOD_NOT_SUPPORTED ||
|
|
ldaperr == LDAP_INVALID_CREDENTIALS )
|
|
|
|
{
|
|
ldaperr = ldap_bind_sA(
|
|
pld,
|
|
NULL,
|
|
NULL,
|
|
LDAP_AUTH_SIMPLE
|
|
);
|
|
|
|
if ( ldaperr != LDAP_SUCCESS )
|
|
{
|
|
uVersion = LDAP_VERSION2;
|
|
|
|
if ( LDAP_SUCCESS == ldap_set_option(pld,
|
|
LDAP_OPT_VERSION,
|
|
&uVersion) )
|
|
{
|
|
ldaperr = ldap_bind_sA(
|
|
pld,
|
|
NULL,
|
|
NULL,
|
|
LDAP_AUTH_SIMPLE
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ldaperr != LDAP_SUCCESS )
|
|
{
|
|
fResult = FALSE;
|
|
|
|
if ( ldaperr != LDAP_LOCAL_ERROR )
|
|
{
|
|
SetLastError( LdapMapErrorToWin32( ldaperr ) );
|
|
}
|
|
// else per Anoop's 4/25/00 email:
|
|
// For LDAP_LOCAL_ERROR, its an underlying security error where
|
|
// LastError has already been updated with a more meaningful error
|
|
// value.
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
#if DBG
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapDisplayUrlComponents
|
|
//
|
|
// Synopsis: display the URL components
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
LdapDisplayUrlComponents (
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
ULONG cCount;
|
|
|
|
printf( "pLdapUrlComponents->pszHost = %s\n", pLdapUrlComponents->pszHost );
|
|
printf( "pLdapUrlComponents->Port = %d\n", pLdapUrlComponents->Port );
|
|
printf( "pLdapUrlComponents->pszDN = %s\n", pLdapUrlComponents->pszDN );
|
|
printf( "pLdapUrlComponents->cAttr = %d\n", pLdapUrlComponents->cAttr );
|
|
|
|
for ( cCount = 0; cCount < pLdapUrlComponents->cAttr; cCount++ )
|
|
{
|
|
printf(
|
|
"pLdapUrlComponents->apszAttr[%d] = %s\n",
|
|
cCount,
|
|
pLdapUrlComponents->apszAttr[cCount]
|
|
);
|
|
}
|
|
|
|
printf( "pLdapUrlComponents->Scope = %d\n", pLdapUrlComponents->Scope );
|
|
printf( "pLdapUrlComponents->pszFilter = %s\n", pLdapUrlComponents->pszFilter );
|
|
}
|
|
#endif
|
|
|