588 lines
13 KiB
C++
588 lines
13 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows NT Security
|
|
// Copyright (C) Microsoft Corporation, 1997 - 1998
|
|
//
|
|
// File: ldapsp.cpp
|
|
//
|
|
// Contents: LDAP Scheme Provider for Remote Object Retrieval
|
|
//
|
|
// History: 23-Jul-97 kirtd Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <aclpch.hxx>
|
|
#pragma hdrstop
|
|
|
|
#include <ldapsp.h>
|
|
#include <shlwapi.h>
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapCrackUrl
|
|
//
|
|
// Synopsis: Crack an LDAP URL into its relevant parts. The result must
|
|
// be freed using LdapFreeUrlComponents
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapCrackUrl (
|
|
LPCWSTR pwszUrl,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
ULONG cbUrl = INTERNET_MAX_PATH_LENGTH;
|
|
LPWSTR pwszHostInfo = NULL;
|
|
LPWSTR pwszDN = NULL;
|
|
LPWSTR pwszAttrList = NULL;
|
|
LPWSTR pwszScope = NULL;
|
|
LPWSTR pwszFilter = NULL;
|
|
LPWSTR pwszToken = NULL;
|
|
WCHAR pwszBuffer[INTERNET_MAX_PATH_LENGTH+1];
|
|
PWCHAR pwsz = pwszBuffer;
|
|
DWORD len = 0;
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Capture the URL and initialize the out parameter
|
|
//
|
|
|
|
if ( wcsncmp( pwszUrl, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) == 0 )
|
|
{
|
|
__try
|
|
{
|
|
hr = UrlCanonicalizeW(
|
|
pwszUrl,
|
|
pwsz,
|
|
&cbUrl,
|
|
ICU_DECODE | URL_WININET_COMPATIBILITY);
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
__except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastError( GetExceptionCode() );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
len = wcslen(pwszUrl);
|
|
|
|
if (len > INTERNET_MAX_PATH_LENGTH)
|
|
{
|
|
pwsz = new WCHAR [len + 1];
|
|
|
|
if (pwsz == NULL)
|
|
{
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
wcscpy(pwsz, pwszUrl);
|
|
}
|
|
|
|
memset( pLdapUrlComponents, 0, sizeof( LDAP_URL_COMPONENTS ) );
|
|
|
|
//
|
|
// Find the host
|
|
//
|
|
|
|
pwszHostInfo = pwsz + sizeof( "ldap://" ) - sizeof( CHAR );
|
|
if ( *pwszHostInfo == L'/' )
|
|
{
|
|
pwszToken = pwszHostInfo + 1;
|
|
pwszHostInfo = NULL;
|
|
}
|
|
else
|
|
{
|
|
pwszHostInfo = wcstok( pwszHostInfo, L"/" );
|
|
}
|
|
|
|
//
|
|
// Find the DN
|
|
//
|
|
|
|
if ( wcsncmp( pwszUrl, LDAP_SCHEME_U, wcslen( LDAP_SCHEME_U ) ) == 0 )
|
|
{
|
|
if ( pwszToken != NULL )
|
|
{
|
|
pwszDN = L"";
|
|
|
|
if ( *pwszToken != L'\0' )
|
|
{
|
|
if ( *pwszToken == L'?' )
|
|
{
|
|
pwszToken += 1;
|
|
}
|
|
else
|
|
{
|
|
pwszDN = pwszToken;
|
|
|
|
do
|
|
{
|
|
pwszToken += 1;
|
|
}
|
|
while ( ( *pwszToken != L'\0' ) && ( *pwszToken != L'?' ) );
|
|
|
|
if ( *pwszToken == L'?' )
|
|
{
|
|
*pwszToken = L'\0';
|
|
pwszToken += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pwszDN = wcstok( pwszToken, L"?" );
|
|
pwszToken = NULL;
|
|
if ( pwszDN == NULL )
|
|
{
|
|
SetLastError( E_INVALIDARG );
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check for attributes
|
|
//
|
|
|
|
if ( pwszToken != NULL )
|
|
{
|
|
if ( *pwszToken == L'?' )
|
|
{
|
|
pwszAttrList = L"";
|
|
pwszToken += 1;
|
|
}
|
|
else if ( *pwszToken == L'\0' )
|
|
{
|
|
pwszAttrList = NULL;
|
|
}
|
|
else
|
|
{
|
|
pwszAttrList = wcstok( pwszToken, L"?" );
|
|
pwszToken = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pwszAttrList = wcstok( NULL, L"?" );
|
|
}
|
|
|
|
//
|
|
// Check for a scope and filter
|
|
//
|
|
|
|
if ( pwszAttrList != NULL )
|
|
{
|
|
pwszScope = wcstok( pwszToken, L"?" );
|
|
if ( pwszScope != NULL )
|
|
{
|
|
pwszFilter = wcstok( NULL, L"?" );
|
|
}
|
|
}
|
|
|
|
if ( pwszScope == NULL )
|
|
{
|
|
pwszScope = L"base";
|
|
}
|
|
|
|
if ( pwszFilter == NULL )
|
|
{
|
|
pwszFilter = L"(objectClass=*)";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( pwszToken != NULL )
|
|
{
|
|
pwszDN = pwszToken;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// pwszDN = wcstok( pwszToken, L"\0" );
|
|
//
|
|
|
|
pwszDN = pwszHostInfo + wcslen( pwszHostInfo ) + 1;
|
|
}
|
|
|
|
pwszAttrList = NULL;
|
|
pwszFilter = L"(objectClass=*)";
|
|
pwszScope = L"base";
|
|
}
|
|
//
|
|
// Now we build up our URL components
|
|
//
|
|
|
|
fResult = LdapParseCrackedHost( pwszHostInfo, pLdapUrlComponents );
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = LdapParseCrackedDN( pwszDN, pLdapUrlComponents );
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = LdapParseCrackedAttributeList(
|
|
pwszAttrList,
|
|
pLdapUrlComponents
|
|
);
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
fResult = LdapParseCrackedScopeAndFilter(
|
|
pwszScope,
|
|
pwszFilter,
|
|
pLdapUrlComponents
|
|
);
|
|
}
|
|
|
|
if ( fResult != TRUE )
|
|
{
|
|
LdapFreeUrlComponents( pLdapUrlComponents );
|
|
}
|
|
|
|
if (pwsz != pwszBuffer)
|
|
{
|
|
delete pwsz;
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedHost
|
|
//
|
|
// Synopsis: Parse the cracked host string (pwszHost is modified)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedHost (
|
|
LPWSTR pwszHost,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
LPWSTR pwszPort;
|
|
|
|
if ( pwszHost == NULL )
|
|
{
|
|
pLdapUrlComponents->pwszHost = NULL;
|
|
pLdapUrlComponents->Port = LDAP_PORT;
|
|
return( TRUE );
|
|
}
|
|
|
|
pwszPort = wcschr( pwszHost, L':' );
|
|
if ( pwszPort != NULL )
|
|
{
|
|
*pwszPort = L'\0';
|
|
pwszPort++;
|
|
}
|
|
|
|
pLdapUrlComponents->pwszHost = new WCHAR [wcslen( pwszHost ) + 1];
|
|
if ( pLdapUrlComponents->pwszHost == NULL )
|
|
{
|
|
SetLastError( E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
wcscpy( pLdapUrlComponents->pwszHost, pwszHost );
|
|
pLdapUrlComponents->Port = 0;
|
|
|
|
if ( pwszPort != NULL )
|
|
{
|
|
pLdapUrlComponents->Port = _wtol( pwszPort );
|
|
}
|
|
|
|
if ( pLdapUrlComponents->Port == 0 )
|
|
{
|
|
pLdapUrlComponents->Port = LDAP_PORT;
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedDN
|
|
//
|
|
// Synopsis: Parse the cracked DN
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedDN (
|
|
LPWSTR pwszDN,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
pLdapUrlComponents->pwszDN = new WCHAR [wcslen( pwszDN ) + 1];
|
|
if ( pLdapUrlComponents->pwszDN == NULL )
|
|
{
|
|
SetLastError( E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
wcscpy( pLdapUrlComponents->pwszDN, pwszDN );
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedAttributeList
|
|
//
|
|
// Synopsis: Parse the cracked attribute list
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedAttributeList (
|
|
LPWSTR pwszAttrList,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
LPWSTR pwsz;
|
|
LPWSTR pwszAttr;
|
|
ULONG cAttr = 0;
|
|
ULONG cCount;
|
|
|
|
if ( ( pwszAttrList == NULL ) || ( wcslen( pwszAttrList ) == 0 ) )
|
|
{
|
|
pLdapUrlComponents->cAttr = 0;
|
|
pLdapUrlComponents->apwszAttr = NULL;
|
|
return( TRUE );
|
|
}
|
|
|
|
pwsz = new WCHAR [wcslen( pwszAttrList ) + 1];
|
|
if ( pwsz == NULL )
|
|
{
|
|
SetLastError( E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
wcscpy( pwsz, pwszAttrList );
|
|
|
|
pwszAttr = wcstok( pwsz, L"," );
|
|
while ( pwszAttr != NULL )
|
|
{
|
|
cAttr += 1;
|
|
pwszAttr = wcstok( NULL, L"," );
|
|
}
|
|
|
|
pLdapUrlComponents->apwszAttr = new LPWSTR [cAttr+1];
|
|
if ( pLdapUrlComponents->apwszAttr == NULL )
|
|
{
|
|
delete pwsz;
|
|
SetLastError( E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
pLdapUrlComponents->cAttr = cAttr;
|
|
for ( cCount = 0; cCount < cAttr; cCount++ )
|
|
{
|
|
pLdapUrlComponents->apwszAttr[cCount] = pwsz;
|
|
pwsz += ( wcslen(pwsz) + 1 );
|
|
}
|
|
|
|
pLdapUrlComponents->apwszAttr[cAttr] = NULL;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapParseCrackedScopeAndFilter
|
|
//
|
|
// Synopsis: Parse the cracked scope and filter
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapParseCrackedScopeAndFilter (
|
|
LPWSTR pwszScope,
|
|
LPWSTR pwszFilter,
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
ULONG Scope;
|
|
|
|
if ( _wcsicmp( pwszScope, L"base" ) == 0 )
|
|
{
|
|
Scope = LDAP_SCOPE_BASE;
|
|
}
|
|
else if ( _wcsicmp( pwszScope, L"one" ) == 0 )
|
|
{
|
|
Scope = LDAP_SCOPE_ONELEVEL;
|
|
}
|
|
else if ( _wcsicmp( pwszScope, L"sub" ) == 0 )
|
|
{
|
|
Scope = LDAP_SCOPE_SUBTREE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( E_INVALIDARG );
|
|
return( FALSE );
|
|
}
|
|
|
|
pLdapUrlComponents->pwszFilter = new WCHAR [wcslen( pwszFilter ) + 1];
|
|
if ( pLdapUrlComponents->pwszFilter == NULL )
|
|
{
|
|
SetLastError( E_OUTOFMEMORY );
|
|
return( FALSE );
|
|
}
|
|
|
|
wcscpy( pLdapUrlComponents->pwszFilter, pwszFilter );
|
|
pLdapUrlComponents->Scope = Scope;
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapFreeUrlComponents
|
|
//
|
|
// Synopsis: Frees allocate URL components returned from LdapCrackUrl
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
LdapFreeUrlComponents (
|
|
PLDAP_URL_COMPONENTS pLdapUrlComponents
|
|
)
|
|
{
|
|
delete pLdapUrlComponents->pwszHost;
|
|
delete pLdapUrlComponents->pwszDN;
|
|
|
|
if ( pLdapUrlComponents->apwszAttr != NULL )
|
|
{
|
|
delete pLdapUrlComponents->apwszAttr[0];
|
|
}
|
|
|
|
delete pLdapUrlComponents->apwszAttr;
|
|
delete pLdapUrlComponents->pwszFilter;
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapGetBindings
|
|
//
|
|
// Synopsis: allocates and initializes the LDAP session binding
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapGetBindings (
|
|
LPWSTR pwszHost,
|
|
ULONG Port,
|
|
DWORD dwRetrievalFlags,
|
|
DWORD dwTimeout,
|
|
LDAP** ppld
|
|
)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
LDAP* pld;
|
|
|
|
pld = ldap_initW( pwszHost, Port );
|
|
if ( pld != NULL )
|
|
{
|
|
ULONG ldaperr;
|
|
|
|
if ( dwTimeout != 0 )
|
|
{
|
|
ldap_set_option( pld, LDAP_OPT_TIMELIMIT, (void *)&dwTimeout );
|
|
}
|
|
|
|
fResult = LdapBindWithOptionalRediscover( pld, pwszHost );
|
|
}
|
|
else
|
|
{
|
|
fResult = FALSE;
|
|
}
|
|
|
|
if ( fResult == TRUE )
|
|
{
|
|
*ppld = pld;
|
|
}
|
|
|
|
return( fResult );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapFreeBindings
|
|
//
|
|
// Synopsis: frees allocated LDAP session binding
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
LdapFreeBindings (
|
|
LDAP* pld
|
|
)
|
|
{
|
|
if ( pld != NULL )
|
|
{
|
|
ldap_unbind_s( pld );
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: LdapBindWithOptionalRediscover
|
|
//
|
|
// Synopsis: bind to the host with optional DC rediscovery if the host is
|
|
// NULL (which means use default via DsGetDcName)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
BOOL
|
|
LdapBindWithOptionalRediscover (LDAP* pld, LPWSTR pwszHost)
|
|
{
|
|
BOOL fResult = TRUE;
|
|
ULONG ldaperr;
|
|
ULONG ldapsaveerr;
|
|
DWORD dwFlags = DS_FORCE_REDISCOVERY;
|
|
|
|
ldaperr = ldap_bind_sW(
|
|
pld,
|
|
NULL,
|
|
NULL,
|
|
LDAP_AUTH_SSPI
|
|
);
|
|
|
|
if ( ( ldaperr != LDAP_SUCCESS ) && ( pwszHost == NULL ) )
|
|
{
|
|
ldapsaveerr = ldaperr;
|
|
|
|
ldaperr = ldap_set_option(
|
|
pld,
|
|
LDAP_OPT_GETDSNAME_FLAGS,
|
|
(LPVOID)&dwFlags
|
|
);
|
|
|
|
if ( ldaperr == LDAP_SUCCESS )
|
|
{
|
|
ldaperr = ldap_bind_sW(
|
|
pld,
|
|
NULL,
|
|
NULL,
|
|
LDAP_AUTH_SSPI
|
|
);
|
|
}
|
|
else
|
|
{
|
|
ldaperr = ldapsaveerr;
|
|
}
|
|
}
|
|
|
|
if ( ldaperr != LDAP_SUCCESS )
|
|
{
|
|
fResult = FALSE;
|
|
SetLastError( LdapMapErrorToWin32(ldaperr) );
|
|
}
|
|
|
|
return( fResult );
|
|
}
|