1293 lines
30 KiB
C++
1293 lines
30 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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 this entry
|
|
//
|
|
|
|
_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){
|
|
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()
|
|
{
|
|
_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);
|
|
}
|
|
}
|
|
|
|
DeleteCriticalSection(&_cs);
|
|
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Function:
|
|
//
|
|
// Synopsis:
|
|
//
|
|
//
|
|
//
|
|
// Arguments:
|
|
//
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
HRESULT
|
|
CObjNameCache::
|
|
CreateClassCache(
|
|
CObjNameCache FAR *FAR * ppClassCache
|
|
)
|
|
{
|
|
CObjNameCache FAR * pClassCache = NULL;
|
|
|
|
pClassCache = new CObjNameCache();
|
|
|
|
if (!pClassCache) {
|
|
RRETURN(E_FAIL);
|
|
}
|
|
|
|
|
|
InitializeCriticalSection(&(pClassCache->_cs));
|
|
|
|
*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;
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
else {
|
|
|
|
//
|
|
// user actually passes in ipaddress as the computer name
|
|
//
|
|
if(IsAddressNumeric(pszElementName)) {
|
|
hr = pgPDCNameCache->addentry(
|
|
pszElementName,
|
|
TRUE,
|
|
COMPUTER_ENTRY_TYPE,
|
|
lpWI->wki100_langroup
|
|
);
|
|
|
|
wcscpy(pszSAMName, L"");
|
|
}
|
|
//
|
|
// user may pass in the dns name of the computer
|
|
//
|
|
else {
|
|
hr = HRESULT_FROM_WIN32(DsRoleGetPrimaryDomainInformation(
|
|
pszElementName,
|
|
DsRolePrimaryDomainInfoBasic, // InfoLevel
|
|
(PBYTE*)&pdomainInfo // pBuffer
|
|
));
|
|
if(SUCCEEDED(hr)) {
|
|
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,
|
|
lpWI->wki100_langroup
|
|
);
|
|
|
|
wcscpy(pszSAMName, L"");
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
BAIL_ON_FAILURE(hr=HRESULT_FROM_WIN32(ERROR_BAD_NETPATH));
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
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] = 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;
|
|
|
|
}
|