Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

317 lines
6.9 KiB

///////////////////////////////////////////////////////////////////////////////
//
// FILE
//
// iasntds.cpp
//
// SYNOPSIS
//
// Defines global objects and functions for the IAS NTDS API.
//
// MODIFICATION HISTORY
//
// 05/11/1998 Original version.
// 07/13/1998 Clean up header file dependencies.
// 08/25/1998 Added IASNtdsQueryUserAttributes.
// 09/02/1998 Added 'scope' parameter to IASNtdsQueryUserAttributes.
// 03/10/1999 Added IASNtdsIsNativeModeDomain.
// 03/23/1999 Retry failed searches.
// 05/11/1999 Ask for at least one attribute or else you get them all.
// 09/14/1999 Move SEARCH_TIMEOUT to LDAPConnection.
//
///////////////////////////////////////////////////////////////////////////////
#include <ias.h>
#include <iasntds.h>
#include <ldapcxn.h>
#include <ntcache.h>
namespace
{
// Global object caches.
NTCache theDomains;
// Initialization reference count.
LONG refCount = 0;
}
DWORD
WINAPI
IASNtdsInitialize( VOID )
{
IASGlobalLockSentry sentry;
++refCount;
return NO_ERROR;
}
VOID
WINAPI
IASNtdsUninitialize( VOID )
{
IASGlobalLockSentry sentry;
if (--refCount == 0)
{
theDomains.clear();
}
}
BOOL
WINAPI
IASNtdsIsNativeModeDomain(
IN PCWSTR domain
)
{
return theDomains.getMode(domain) == NTDomain::MODE_NATIVE;
}
//////////
// Retrieve a single entry from the DS. Handles all clean-up on failure.
//////////
DWORD
WINAPI
GetSingleEntry(
LDAPConnection* cxn,
PWCHAR base,
ULONG scope,
PWCHAR filter,
PWCHAR attrs[],
LDAPMessage **res
) throw ()
{
//////////
// Perform the search.
//////////
ULONG error = ldap_search_ext_sW(
*cxn,
base,
scope,
filter,
attrs,
FALSE,
NULL,
NULL,
&LDAPConnection::SEARCH_TIMEOUT,
0,
res
);
//////////
// Process the results.
//////////
if (error != LDAP_SUCCESS && error != LDAP_PARTIAL_RESULTS)
{
cxn->TraceFailure("ldap_search_ext_sW", error);
cxn->disable();
error = LdapMapErrorToWin32(error);
}
else if ((*res)->lm_returncode != LDAP_SUCCESS)
{
error = LdapMapErrorToWin32((*res)->lm_returncode);
cxn->TraceFailure("ldap_search_ext_sW", (*res)->lm_returncode);
}
else if (ldap_count_entries(*cxn, *res) != 1)
{
error = ERROR_NO_SUCH_USER;
}
else
{
return NO_ERROR;
}
//////////
// The search failed, so clean-up.
//////////
if (*res != NULL)
{
ldap_msgfree(*res);
*res = NULL;
}
return error;
}
//////////
// Constants used for building LDAP search filters.
//////////
const WCHAR USER_FILTER_PREFIX[] = L"(sAMAccountName=";
const WCHAR USER_FILTER_SUFFIX[] = L")";
const size_t MAX_USERNAME_LENGTH = 256;
const size_t USER_FILTER_LENGTH = sizeof(USER_FILTER_PREFIX)/sizeof(WCHAR) +
MAX_USERNAME_LENGTH +
sizeof(USER_FILTER_SUFFIX)/sizeof(WCHAR);
//////////
// Empty attribute list.
//////////
PWCHAR NO_ATTRS[] = { L"cn", NULL };
DWORD
WINAPI
QueryUserAttributesOnce(
IN PCWSTR domainName,
IN PCWSTR username,
IN ULONG scope,
IN PWCHAR attrs[],
OUT PIAS_NTDS_RESULT result
)
{
//////////
// Retrieve a connection to the domain.
//////////
CComPtr<LDAPConnection> cxn;
DWORD error = theDomains.getConnection(domainName, &cxn);
switch (error)
{
case NO_ERROR:
{
IASTracePrintf("Sending LDAP search to %s.", cxn->getHost());
break;
}
case ERROR_DS_NOT_INSTALLED:
{
IASTracePrintf("DS not installed for domain %S.", domainName);
return error;
}
default:
{
IASTracePrintf("Could not open an LDAP connection to domain %S.",
domainName);
IASTraceFailure("NTDomain::getConnection", error);
return error;
}
}
//////////
// Initialize the search filter.
//////////
WCHAR searchFilter[USER_FILTER_LENGTH];
wcscpy (searchFilter, USER_FILTER_PREFIX);
wcsncat(searchFilter, username, MAX_USERNAME_LENGTH);
wcscat (searchFilter, USER_FILTER_SUFFIX);
//////////
// Query the DS. If scope == LDAP_SCOPE_BASE, then we won't retrieve the
// actual attributes yet.
//////////
LDAPMessage* res;
error = GetSingleEntry(
cxn,
const_cast<PWCHAR>(cxn->getBase()),
LDAP_SCOPE_SUBTREE,
searchFilter,
(scope == LDAP_SCOPE_BASE ? NO_ATTRS : attrs),
&res
);
if (error == NO_ERROR && scope == LDAP_SCOPE_BASE)
{
// All we care about is the user's DN.
PWCHAR dn = ldap_get_dnW(*cxn, ldap_first_entry(*cxn, res));
ldap_msgfree(res);
// Now get the actual attributes.
error = GetSingleEntry(
cxn,
dn,
LDAP_SCOPE_BASE,
L"(objectclass=*)",
attrs,
&res
);
ldap_memfree(dn);
}
if (error == NO_ERROR)
{
LDAPConnection* rawCxn = cxn;
rawCxn->AddRef();
result->cxn = rawCxn;
result->msg = res;
}
return error;
}
DWORD
WINAPI
IASNtdsQueryUserAttributes(
IN PCWSTR domainName,
IN PCWSTR username,
IN ULONG scope,
IN PWCHAR attrs[],
OUT PIAS_NTDS_RESULT result
)
{
if (result == 0)
{
return ERROR_INVALID_PARAMETER;
}
result->cxn = 0;
result->msg = 0;
DWORD retval = QueryUserAttributesOnce(
domainName,
username,
scope,
attrs,
result
);
switch (retval)
{
case NO_ERROR:
case ERROR_DS_NOT_INSTALLED:
case ERROR_NO_SUCH_USER:
case ERROR_ACCESS_DENIED:
return retval;
}
IASTraceString("Retrying LDAP search.");
return QueryUserAttributesOnce(
domainName,
username,
scope,
attrs,
result
);
}
VOID
WINAPI
IASNtdsFreeResult(
PIAS_NTDS_RESULT result
)
{
if (result != 0)
{
if (result->cxn != 0)
{
static_cast<LDAPConnection*>(result->cxn)->Release();
result->cxn = 0;
}
if (result->msg != 0)
{
ldap_msgfree(result->msg);
result->msg = 0;
}
}
}