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.
 
 
 
 
 
 

1383 lines
34 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: cpdccach.cxx
//
// Contents: PDC Names Cache functionality for the WinNT Provider
//
// Functions:
// CObjNameCache::addentry
// CObjNameCache::findentry
// CObjNameCache::getentry
// CProperyCache::CObjNameCache
// CObjNameCache::~CObjNameCache
// CObjNameCache::CreateClassCache
//
// History: 25-Apr-96 KrishnaG Created.
// 30-Aug-96 RamV Permit cache to store values
// other than PDC names
//
//----------------------------------------------------------------------------
#include "winnt.hxx"
//
// Definition for DsGetDcName on 4.0
//
typedef DWORD (*PF_DsGetDcName) (
IN LPCWSTR ComputerName OPTIONAL,
IN LPCWSTR DomainName OPTIONAL,
IN GUID *DomainGuid OPTIONAL,
IN LPCWSTR SiteName OPTIONAL,
IN ULONG Flags,
OUT PDOMAIN_CONTROLLER_INFO *DomainControllerInfo
);
#ifdef UNICODE
#define GETDCNAME_API "DsGetDcNameW"
#else
#define GETDCNAME_API "DsGetDcNameA"
#endif
//
// DsGetDc will be called if applicabel if not we will look
// at the flags and decide if we should call NetGetAnyDCName or
// NetGetDCName - AjayR 11-04-98.
// Note the code below is not exactly "elegant" but I cannot think
// of any other way to build on 4.0, 95 and NT. Please play close
// attention to the #ifdefs when reading.
//
HRESULT
DsGetDcNameNTWrapper(
IN LPCWSTR DomainName,
OUT LPWSTR *ppszServerName,
IN ULONG Flags
)
{
LPCWSTR ComputerName = NULL;
GUID *DomainGuid = NULL;
LPCWSTR SiteName = NULL;
PDOMAIN_CONTROLLER_INFO pDomainControllerInfo = NULL;
DWORD dwStatus = NULL;
LPWSTR pszNetServerName = NULL;
HRESULT hr = S_OK;
ULONG ulDsGetDCFlags = DS_RETURN_FLAT_NAME | DS_WRITABLE_REQUIRED;
if (Flags & ADS_READONLY_SERVER) {
ulDsGetDCFlags &= ~DS_WRITABLE_REQUIRED;
}
*ppszServerName = NULL;
static PF_DsGetDcName pfDsGetDcName = NULL ;
//
// Load the function if necessary
//
if (pfDsGetDcName == NULL) {
pfDsGetDcName =
(PF_DsGetDcName) LoadNetApi32Function(GETDCNAME_API) ;
}
if (pfDsGetDcName != NULL) {
dwStatus = ((*pfDsGetDcName)(
ComputerName,
DomainName,
DomainGuid,
SiteName,
ulDsGetDCFlags,
&pDomainControllerInfo
)
);
if (dwStatus == NO_ERROR) {
*ppszServerName = AllocADsStr(
pDomainControllerInfo->DomainControllerName
);
if (!*ppszServerName)
hr = E_OUTOFMEMORY;
} else {
hr = HRESULT_FROM_WIN32(dwStatus);
}
} else {
//
// Could not load library
//
if (Flags & ADS_READONLY_SERVER) {
#ifdef WIN95
dwStatus = NetGetDCName(
NULL,
DomainName,
(LPBYTE *)&pszNetServerName
);
#else
dwStatus = NetGetAnyDCName(
NULL,
DomainName,
(LPBYTE *)&pszNetServerName
);
#endif
} else {
dwStatus = NetGetDCName(
NULL,
DomainName,
(LPBYTE *)&pszNetServerName
);
}
if (dwStatus == NO_ERROR) {
*ppszServerName = AllocADsStr(
pszNetServerName
);
if (!*ppszServerName)
hr = E_OUTOFMEMORY;
} else {
hr = HRESULT_FROM_WIN32(dwStatus);
}
}
if (pszNetServerName) {
(void) NetApiBufferFree( (void*) pszNetServerName);
}
if (pDomainControllerInfo) {
(void) NetApiBufferFree(pDomainControllerInfo);
}
RRETURN(hr);
}
//+------------------------------------------------------------------------
//
// Function: CObjNameCache::addentry
//
// Synopsis:
//
//
//
// Arguments: [pszDomainName] --
// [pszPDCName] --
// [pClassEntry] --
//
//
//-------------------------------------------------------------------------
HRESULT
CObjNameCache::
addentry(
LPWSTR pszElementName,
BOOL fCacheHit,
DWORD dwElementType,
LPWSTR pszName
)
{
//
// The parameter pszName is either the Domain/Wkgrp Name (if dwElementType
// = COMPUTER_ENTRY_TYPE) and PDC Name (if dwElementType is
// DOMAIN_ENTRY_TYPE). it will be a blank string if dwElementType is
// WORKGROUP_ENTRY_TYPE
//
// we will support adding cache hits/misses.
//
HRESULT hr = S_OK;
DWORD i = 0;
DWORD dwLRUEntry = 0;
DWORD dwIndex = 0;
EnterCriticalSection(&_cs);
//
// before adding entries, let us clean out all existing old entries
//
if (_dwMaxCacheSize == 0){
hr = E_FAIL;
goto error;
}
hr = InvalidateStaleEntries();
BAIL_ON_FAILURE(hr);
hr = findentry(
pszElementName,
&dwIndex
);
//
// if you find an entry then you cannot add it to the cache
//
if(SUCCEEDED(hr)){
goto error;
}
hr = S_OK;
for (i = 0; i < _dwMaxCacheSize; i++ ) {
if (!_ClassEntries[i].bInUse) {
//
// Found an available entry; use it
// fill in the name of the entry and related information
// for this class entry
//
break;
} else {
if ((dwLRUEntry == -1) || (i == IsOlderThan(i, dwLRUEntry))){
dwLRUEntry = i;
}
}
}
if (i == _dwMaxCacheSize){
//
// We have no available entries so we need to use
// the LRUEntry which is busy
//
//
// Free the members of the LRU Entry
//
if (_ClassEntries[dwLRUEntry].pszElementName)
{
FreeADsStr(_ClassEntries[dwLRUEntry].pszElementName);
_ClassEntries[dwLRUEntry].pszElementName = NULL;
}
//
// All members of the union are strings so it is not
// necessary to check for each of the members. Just free
// one of them if it is non-null.
//
if(_ClassEntries[i].u.pszPDCName)
{
FreeADsStr(_ClassEntries[i].u.pszPDCName);
_ClassEntries[i].u.pszPDCName = NULL;
}
_ClassEntries[dwLRUEntry].bInUse = FALSE;
i = dwLRUEntry;
}
//
// Insert the new entry into the Cache
//
_ClassEntries[i].pszElementName = AllocADsStr(pszElementName);
if(_ClassEntries[i].pszElementName == NULL){
hr = E_OUTOFMEMORY;
goto error;
}
_ClassEntries[i].dwElementType = dwElementType;
if ( fCacheHit){
_ClassEntries[i].fCacheHit = TRUE;
switch(dwElementType) {
case DOMAIN_ENTRY_TYPE:
_ClassEntries[i].u.pszPDCName = AllocADsStr(pszName);
if(_ClassEntries[i].u.pszPDCName == NULL){
hr = E_OUTOFMEMORY;
goto error;
}
break;
case DOMAIN_ENTRY_TYPE_RO:
_ClassEntries[i].u.pszDCName = AllocADsStr(pszName);
if (_ClassEntries[i].u.pszDCName == NULL) {
hr = E_OUTOFMEMORY;
goto error;
}
break;
case COMPUTER_ENTRY_TYPE:
_ClassEntries[i].u.pszDomainName = AllocADsStr(pszName);
if(_ClassEntries[i].u.pszDomainName == NULL){
hr = E_OUTOFMEMORY;
goto error;
}
break;
default:
break;
}
} else {
_ClassEntries[i].fCacheHit = FALSE;
}
_ClassEntries[i].bInUse = TRUE;
//
// update the time stamp so that we know when this entry was made
//
GetSystemTime(&_ClassEntries[i].st);
error:
LeaveCriticalSection(&_cs);
RRETURN(hr);
}
//+------------------------------------------------------------------------
//
// Function: CObjNameCache::findentry
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] --
// [pdwIndex] --
//
//-------------------------------------------------------------------------
HRESULT
CObjNameCache::
findentry(
LPWSTR pszElementName,
PDWORD pdwIndex
)
{
DWORD i = 0;
EnterCriticalSection(&_cs);
if (_dwMaxCacheSize == 0 ) {
LeaveCriticalSection(&_cs);
RRETURN(E_FAIL);
}
for (i = 0; i < _dwMaxCacheSize; i++ ) {
if (_ClassEntries[i].bInUse) {
if(!_ClassEntries[i].pszElementName ){
continue;
}
#ifdef WIN95
if (!_wcsicmp(_ClassEntries[i].pszElementName, pszElementName)){
#else
if (CompareStringW(
LOCALE_SYSTEM_DEFAULT,
NORM_IGNORECASE,
_ClassEntries[i].pszElementName,
-1,
pszElementName,
-1
) == CSTR_EQUAL ) {
#endif
*pdwIndex = i;
LeaveCriticalSection(&_cs);
RRETURN(S_OK);
}
}
}
LeaveCriticalSection(&_cs);
RRETURN(E_FAIL);
}
//+------------------------------------------------------------------------
//
// Function: CObjNameCache::getentry
//
// Synopsis:
//
//
//
// Arguments: [szPropertyName] --
// [pdwIndex] --
//
//-------------------------------------------------------------------------
HRESULT
CObjNameCache::
getentry(
LPWSTR pszElementName,
PBOOL pfHit,
PDWORD pdwEntryType,
LPWSTR pszName
)
{
DWORD dwIndex = 0;
HRESULT hr = S_OK;
DWORD i;
EnterCriticalSection(&_cs);
//
// blow away all the entries that have expired
//
hr = InvalidateStaleEntries();
BAIL_ON_FAILURE(hr);
hr = findentry(
pszElementName,
&dwIndex
);
BAIL_ON_FAILURE(hr);
*pfHit = _ClassEntries[dwIndex].fCacheHit;
*pdwEntryType = _ClassEntries[dwIndex].dwElementType;
switch(_ClassEntries[dwIndex].dwElementType) {
case DOMAIN_ENTRY_TYPE:
wcscpy(pszName, _ClassEntries[dwIndex].u.pszPDCName);
break;
case COMPUTER_ENTRY_TYPE:
wcscpy(pszName, _ClassEntries[dwIndex].u.pszDomainName);
break;
case DOMAIN_ENTRY_TYPE_RO:
wcscpy(pszName, _ClassEntries[dwIndex].u.pszDCName);
break;
default:
wcscpy(pszName, TEXT(""));
break;
}
error:
LeaveCriticalSection(&_cs);
RRETURN(hr);
}
HRESULT
CObjNameCache::
InvalidateStaleEntries()
{
DWORD i=0;
SYSTEMTIME stCurrentTime;
BOOL fCacheHit;
GetSystemTime(&stCurrentTime);
for ( i=0; i< _dwMaxCacheSize; i++){
fCacheHit = _ClassEntries[i].fCacheHit;
if(_ClassEntries[i].bInUse &&
TimeDifference(stCurrentTime, _ClassEntries[i].st)
> AGE_LIMIT_VALID_ENTRIES && fCacheHit == CACHE_HIT) {
_ClassEntries[i].bInUse = FALSE;
FreeADsStr(_ClassEntries[i].pszElementName);
_ClassEntries[i].pszElementName = NULL;
if((_ClassEntries[i].dwElementType == DOMAIN_ENTRY_TYPE) ||
(_ClassEntries[i].dwElementType == DOMAIN_ENTRY_TYPE_RO))
{
FreeADsStr(_ClassEntries[i].u.pszPDCName);
_ClassEntries[i].u.pszPDCName = NULL;
} else if (_ClassEntries[i].dwElementType == COMPUTER_ENTRY_TYPE){
FreeADsStr(_ClassEntries[i].u.pszDomainName);
_ClassEntries[i].u.pszPDCName = NULL;
}
}else if(_ClassEntries[i].bInUse &&
TimeDifference(stCurrentTime, _ClassEntries[i].st)
> AGE_LIMIT_INVALID_ENTRIES && fCacheHit == CACHE_MISS) {
_ClassEntries[i].bInUse = FALSE;
}
}
RRETURN(S_OK);
}
//+------------------------------------------------------------------------
//
// Function: CObjNameCache
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
CObjNameCache::CObjNameCache() :
_fCriticalSectionInitialized(FALSE)
{
_dwMaxCacheSize = 10;
memset(_ClassEntries, 0, sizeof(CLASSENTRY)* MAX_ENTRIES);
}
//+------------------------------------------------------------------------
//
// Function: ~CObjNameCache
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
CObjNameCache::
~CObjNameCache()
{
DWORD i= 0;
for (i=0; i< MAX_ENTRIES; i++){
if(_ClassEntries[i].pszElementName){
FreeADsStr(_ClassEntries[i].pszElementName);
}
//
// All members of the union are strings so it is not
// necessary to check for each of the members.
//
if(_ClassEntries[i].u.pszPDCName){
FreeADsStr(_ClassEntries[i].u.pszPDCName);
}
}
if (_fCriticalSectionInitialized)
DeleteCriticalSection(&_cs);
}
//+------------------------------------------------------------------------
//
// Function:
//
// Synopsis:
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
HRESULT
CObjNameCache::
CreateClassCache(
CObjNameCache FAR *FAR * ppClassCache
)
{
CObjNameCache FAR * pClassCache = NULL;
pClassCache = new CObjNameCache();
if (!pClassCache) {
RRETURN(E_FAIL);
}
__try
{
InitializeCriticalSection(&(pClassCache->_cs));
pClassCache->_fCriticalSectionInitialized = TRUE;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
RRETURN(E_OUTOFMEMORY);
}
*ppClassCache = pClassCache;
RRETURN(S_OK);
}
DWORD
CObjNameCache::
IsOlderThan(
DWORD i,
DWORD j
)
{
SYSTEMTIME *pi, *pj;
DWORD iMs, jMs;
// DBGMSG(DBG_TRACE, ("IsOlderThan entering with i %d j %d\n", i, j));
pi = &(_ClassEntries[i].st);
pj = &(_ClassEntries[j].st);
if (pi->wYear < pj->wYear) {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
return(i);
} else if (pi->wYear > pj->wYear) {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
return(j);
} else if (pi->wMonth < pj->wMonth) {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
return(i);
} else if (pi->wMonth > pj->wMonth) {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
return(j);
} else if (pi->wDay < pj->wDay) {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
return(i);
} else if (pi->wDay > pj->wDay) {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
return(j);
} else {
iMs = ((((pi->wHour * 60) + pi->wMinute)*60) + pi->wSecond)* 1000 + pi->wMilliseconds;
jMs = ((((pj->wHour * 60) + pj->wMinute)*60) + pj->wSecond)* 1000 + pj->wMilliseconds;
if (iMs <= jMs) {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", i));
return(i);
} else {
// DBGMSG(DBG_TRACE, ("IsOlderThan returns %d\n", j));
return(j);
}
}
}
HRESULT
WinNTGetCachedDCName(
LPWSTR pszDomainName,
LPWSTR pszPDCName,
DWORD dwFlags
)
{
WCHAR szSAMName[MAX_PATH];
// In this case credentials do not help because we do not have
// any server/domain to connect to. This is because the param
// pszDomainName is not a domain name for certain.
CWinNTCredentials nullCredentials;
// We do want to copy the flags parameter as that will tell
// us if we need to connect to PDC or not
nullCredentials.SetFlags(dwFlags);
RRETURN(WinNTGetCachedObject(pszDomainName,
DOMAIN_ENTRY_TYPE,
pszPDCName,
szSAMName,
dwFlags,
nullCredentials
));
}
HRESULT
WinNTGetCachedComputerName(
LPWSTR pszComputerName,
LPWSTR pszName,
LPWSTR pszSAMName,
CWinNTCredentials& Credentials
)
{
RRETURN(WinNTGetCachedObject(pszComputerName,
COMPUTER_ENTRY_TYPE,
pszName,
pszSAMName,
Credentials.GetFlags(), // doesnt matter
Credentials
));
}
HRESULT
WinNTGetCachedObject(
LPWSTR pszElementName,
DWORD dwElementType,
LPWSTR pszName,
LPWSTR pszSAMName,
DWORD dwFlags,
CWinNTCredentials& Credentials
)
{
HRESULT hr = S_OK;
NET_API_STATUS nasStatus = 0;
BOOL fCacheHit;
DWORD dwEntryType;
LPWKSTA_INFO_100 lpWI = NULL;
DWORD dwObjectsReturned;
DWORD dwObjectsTotal;
DWORD dwResumeHandle;
// Freed using NetAPI
LPWSTR pszServerName = NULL;
// Freed using FreeADsStr
LPWSTR pszADsStrServerName = NULL;
BOOL fRefAdded = FALSE;
DWORD dwDomainEntryType = DOMAIN_ENTRY_TYPE;
// This will be the case most often
DWORD dwUserFlags = Credentials.GetFlags();
DSROLE_PRIMARY_DOMAIN_INFO_BASIC* pdomainInfo = NULL;
BOOL fNetBIOS = FALSE;
BOOL fDsRoleCallAttempted = FALSE;
hr = pgPDCNameCache->getentry(
pszElementName,
&fCacheHit,
&dwEntryType,
pszName
);
if (SUCCEEDED(hr)) {
//
// we found the entry. Now need to verify that it indeed
// is an object of type desired
//
// Note that dwElement type will never be DOMAIN_ENTRY_TYPE_RO
if(fCacheHit) {
if (dwEntryType == dwElementType
|| ((dwElementType == DOMAIN_ENTRY_TYPE)
&& (dwEntryType == DOMAIN_ENTRY_TYPE_RO)
&& (dwUserFlags & ADS_READONLY_SERVER))
) {
//
// If the user now needs a writeable connection
// should we fail or should we actually pretend
// that the object is not there in the cache.
//
hr = S_OK;
goto error;
}
} else if (!fCacheHit && (dwElementType == WORKGROUP_ENTRY_TYPE)) {
//
// looks like we either found a cache miss
// Return ok
//
hr = S_OK;
goto error;
} else {
hr = E_FAIL;
goto error;
}
}
switch(dwElementType){
case DOMAIN_ENTRY_TYPE:
//
// A read only server is ok, need to also set the
// domain entry type accordingly
//
if (dwFlags & ADS_READONLY_SERVER) {
dwDomainEntryType = DOMAIN_ENTRY_TYPE_RO;
}
//
// Call the all encompassing Wrapper.
//
hr = DsGetDcNameNTWrapper(
pszElementName,
&pszADsStrServerName,
dwFlags
);
BAIL_ON_FAILURE(hr);
hr = pgPDCNameCache->addentry(
pszElementName,
TRUE,
dwDomainEntryType,
pszADsStrServerName
);
BAIL_ON_FAILURE(hr);
//
// in addition we can also add a computer entry for the PDC
//
hr = pgPDCNameCache->addentry(
pszADsStrServerName+2, // to get rid of the leading backslashes
TRUE,
COMPUTER_ENTRY_TYPE,
pszElementName
);
BAIL_ON_FAILURE(hr);
wcscpy(pszName, pszADsStrServerName);
break;
case COMPUTER_ENTRY_TYPE:
// Ref the computer, note that RefServer will not
// do anything if the credentials are null. We are also
// not worried about errors as we want to use default
// credentials in that case.
hr = Credentials.RefServer(pszElementName);
if (SUCCEEDED(hr)) {
fRefAdded = TRUE;
}
nasStatus = NetWkstaGetInfo(
pszElementName,
100,
(LPBYTE*) &lpWI
);
hr = HRESULT_FROM_WIN32(nasStatus);
BAIL_ON_FAILURE(hr);
#ifdef WIN95
//
// No NetpNameCompare for Win9x
//
if (lpWI->wki100_computername
&& (_wcsicmp(pszElementName, lpWI->wki100_computername) == 0)
)
#else
if (lpWI->wki100_computername
&& ( NetpNameCompare(
NULL,
pszElementName,
lpWI->wki100_computername,
NAMETYPE_COMPUTER,
0
)
== 0 )
)
#endif
{
// Want to add the correct capitalized name
// Not what the user gave
hr = pgPDCNameCache->addentry(
lpWI->wki100_computername,
TRUE,
COMPUTER_ENTRY_TYPE,
lpWI->wki100_langroup
);
wcscpy(pszSAMName, lpWI->wki100_computername);
fNetBIOS = TRUE;
}
else {
DsRoleGetPrimaryDomainInformation(
pszElementName,
DsRolePrimaryDomainInfoBasic, // InfoLevel
(PBYTE*)&pdomainInfo // pBuffer
);
fDsRoleCallAttempted = TRUE;
// we don't bail out even if the call fails
//
// user actually passes in ipaddress as the computer name
//
if(IsAddressNumeric(pszElementName)) {
hr = pgPDCNameCache->addentry(
pszElementName,
TRUE,
COMPUTER_ENTRY_TYPE,
pdomainInfo && pdomainInfo->DomainNameDns ? pdomainInfo->DomainNameDns : lpWI->wki100_langroup
);
wcscpy(pszSAMName, L"");
}
//
// user may pass in the dns name of the computer
//
else {
if(pdomainInfo) {
if(((pdomainInfo->DomainNameDns) && _wcsicmp(pszElementName, pdomainInfo->DomainNameDns) == 0)
||
((pdomainInfo->DomainNameFlat) && NetpNameCompare(
NULL,
pszElementName,
pdomainInfo->DomainNameFlat,
NAMETYPE_COMPUTER,
0
)
== 0) )
{
BAIL_ON_FAILURE(hr=HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
}
else {
hr = pgPDCNameCache->addentry(
pszElementName,
TRUE,
COMPUTER_ENTRY_TYPE,
pdomainInfo->DomainNameDns
);
wcscpy(pszSAMName, L"");
}
}
else {
BAIL_ON_FAILURE(hr=HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
}
}
}
// we need to return the correct format of domain name
if(!(*pszName))
{
// the parent name is NULL
if(fNetBIOS)
{
// if the user specifies the computer netbios name, then we just return the domain netbios name
wcscpy(pszName, lpWI->wki100_langroup);
}
else
{
// othereise we tries to return the domain dns name
wcscpy(pszName, pdomainInfo && pdomainInfo->DomainNameDns ? pdomainInfo->DomainNameDns : lpWI->wki100_langroup);
}
}
else
{
// we have the parent name passed in, so we need to return pszName accordingly
if (lpWI->wki100_langroup
&& ( NetpNameCompare(
NULL,
pszName,
lpWI->wki100_langroup,
NAMETYPE_DOMAIN,
0
)
))
{
// the parent name passed in is not equal to the domain netbios name
if(!fDsRoleCallAttempted)
{
DsRoleGetPrimaryDomainInformation(
pszElementName,
DsRolePrimaryDomainInfoBasic, // InfoLevel
(PBYTE*)&pdomainInfo // pBuffer
);
}
// unless the the parent name passed in is equal to the domain dns name, we just put domain netbios name
// to the pszName
if(!(pdomainInfo && pdomainInfo->DomainNameDns && !_wcsicmp(pszName, pdomainInfo->DomainNameDns)))
{
// the parent name passed in is not equal to the domain dns name also
wcscpy(pszName, lpWI->wki100_langroup);
}
}
}
break;
default:
hr = E_FAIL;
break;
}
error:
if (fRefAdded) {
Credentials.DeRefServer();
// even if we fail, we have no recovery path
fRefAdded = FALSE;
}
if(lpWI){
NetApiBufferFree(lpWI);
}
if(pszServerName){
NetApiBufferFree(pszServerName);
}
if (pszADsStrServerName) {
FreeADsStr(pszADsStrServerName);
}
if ( pdomainInfo )
{
DsRoleFreeMemory(pdomainInfo);
}
RRETURN(hr);
}
//+------------------------------------------------------------------------
//
// Function:
//
// Synopsis:
// This function is called by Heuristic GetObject to identify what
// kind of object we are dealing with. Here we try to get a cached
// entry if it is a hit/miss. If it fails, then we try each kind
// of object in turn. (Domain/Computer/Workgroup). Once we do this,
// we cache this information internally
//
//
//
// Arguments:
//
//
//-------------------------------------------------------------------------
HRESULT
WinNTGetCachedName(
LPWSTR pszElementName,
PDWORD pdwElementType,
LPWSTR pszName,
LPWSTR pszSAMName,
CWinNTCredentials& Credentials
)
{
HRESULT hr = S_OK;
BOOL fCacheHit;
DWORD dwEntryType;
WCHAR szSAMName[MAX_ADS_PATH];
BOOL fRefAdded = FALSE;
DWORD dwUserFlags = Credentials.GetFlags();
szSAMName[0] = pszName[0] = L'\0';
if (!pszElementName || !*pszElementName) {
RRETURN(E_FAIL);
}
hr = pgPDCNameCache->getentry(
pszElementName,
&fCacheHit,
&dwEntryType,
pszName
);
if (SUCCEEDED(hr)) {
//
// we found the entry.
//
if (!fCacheHit){
//
// cache miss saved as a workgroup
//
*pdwElementType = WORKGROUP_ENTRY_TYPE;
goto error;
} else {
if(dwEntryType == DOMAIN_ENTRY_TYPE_RO) {
if(dwUserFlags & ADS_READONLY_SERVER) {
// HeuristicGetObj doesn't recognize DOMAIN_ENTRY_TYPE_RO
*pdwElementType = DOMAIN_ENTRY_TYPE;
goto error;
}
}
else {
*pdwElementType = dwEntryType;
goto error;
}
}
}
{
// at this point, we can try and ref the domain as
// we are looking to bind to the domain
hr = Credentials.RefDomain(pszElementName);
// note that even if this fails we want to continue
// as there is the chance that the current users
// credentials are good enough for the operation
if (SUCCEEDED(hr)) {
fRefAdded = TRUE;
}
hr = WinNTGetCachedObject(
pszElementName,
DOMAIN_ENTRY_TYPE,
pszName,
szSAMName,
Credentials.GetFlags(),
Credentials
);
if (fRefAdded) {
Credentials.DeRefDomain();
// we cannot really do anything useful with HR
fRefAdded = FALSE;
}
if (SUCCEEDED(hr)){
*pdwElementType = DOMAIN_ENTRY_TYPE;
wcscpy(pszSAMName, szSAMName);
RRETURN(hr);
}
hr = WinNTGetCachedObject(
pszElementName,
COMPUTER_ENTRY_TYPE,
pszName,
szSAMName,
Credentials.GetFlags(),
Credentials
);
if (SUCCEEDED(hr)){
*pdwElementType = COMPUTER_ENTRY_TYPE;
wcscpy(pszSAMName, szSAMName);
RRETURN(hr);
}
//
// if you are here, it means that you have to cache a miss as a
// workgroup.
// Note that pszSAMName rather than pszElementName is added
// if it is valid
// AjayR - to handle the no workstation case,
// We should not add anything if the error was NOWksta service
if (hr != HRESULT_FROM_WIN32(NERR_WkstaNotStarted)) {
if (szSAMName[0] != L'\0') {
hr = pgPDCNameCache->addentry(
szSAMName,
FALSE,
WORKGROUP_ENTRY_TYPE,
TEXT("")
);
} else {
hr = pgPDCNameCache->addentry(
pszElementName,
FALSE,
WORKGROUP_ENTRY_TYPE,
TEXT("")
);
}
} // No Wksta started
*pdwElementType = WORKGROUP_ENTRY_TYPE;
wcscpy(pszName, TEXT(""));
goto error;
}
error:
RRETURN(hr);
}
LONG
TimeDifference(
SYSTEMTIME st1,
SYSTEMTIME st2
)
{
//
// This function gives the difference between st1 and st2 (st1-st2)in secs.
// This will be used by our internal cache object so as to find out if
// a certain entry in the cache is too old.
// Assumption: st1 is later than st2.
DWORD dwTime1;
DWORD dwTime2;
DWORD dwMonth1;
DWORD dwMonth2;
LONG lRetval;
//
// Ignore milliseconds because it is immaterial for our purposes
//
dwTime1= st1.wSecond + 60 *
(st1.wMinute + 60* (st1.wHour + 24 * (st1.wDay)));
dwTime2= st2.wSecond + 60 *
(st2.wMinute + 60* (st2.wHour + 24 * (st2.wDay)));
if (dwTime1 == dwTime2) {
return(0);
}
if (dwTime1 > dwTime2 && (st1.wMonth == st2.wMonth) &&
st1.wYear == st2.wYear) {
lRetval = (LONG)(dwTime1-dwTime2);
goto cleanup;
}
dwMonth1 = 12*st1.wYear+ st1.wMonth;
dwMonth2 = 12*st2.wYear+ st2.wMonth;
if (dwMonth1 < dwMonth2) {
//
// looks like we got a bogus value. return -1
//
lRetval = -1;
goto cleanup;
}
//
// if there is a month difference of more than 1 then we return
// a large positive number (0xFFFFFFF)
//
if (dwMonth1 > dwMonth2+1) {
lRetval = 0xFFFFFFF;
goto cleanup;
}
//
// we crossed a month boundary
//
dwTime1= st1.wSecond + 60 *
(st1.wMinute + 60* (st1.wHour));
dwTime2= st2.wSecond + 60 *
(st2.wMinute);
lRetval = ( dwTime2- dwTime1 + 60*60*24);
goto cleanup;
cleanup:
return(lRetval);
}
BOOL
IsAddressNumeric(
LPWSTR HostName
)
{
BOOLEAN rc = FALSE;
//
// to check to see if it's a TCP address, we check for it to only
// contain only numerals and periods.
//
while (((*HostName >= L'0') && (*HostName <= L'9')) ||
(*HostName == L'.')) {
HostName++;
}
//
// if we hit the end of the hostname, then it's an address.
//
if (*HostName == L'\0' || *HostName == L':') {
rc = TRUE;
}
return rc;
}