windows-nt/Source/XPSP1/NT/ds/security/ntmarta/newsrc/ldapsp.cpp
2020-09-26 16:20:57 +08:00

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 );
}