mirror of https://github.com/tongzx/nt5src
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.
1019 lines
20 KiB
1019 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1997-2001 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
remote.c
|
|
|
|
Abstract:
|
|
|
|
DNS Resolver Service.
|
|
|
|
Remote APIs to resolver service.
|
|
|
|
Author:
|
|
|
|
Glenn Curtis (glennc) Feb 1997
|
|
|
|
Revision History:
|
|
|
|
Jim Gilroy (jamesg) March 2000 cleanup
|
|
|
|
--*/
|
|
|
|
|
|
#include "local.h"
|
|
|
|
|
|
//
|
|
// Local Definitions
|
|
//
|
|
|
|
typedef struct _POPUP_MSG_PARMS
|
|
{
|
|
LPWSTR Message;
|
|
LPWSTR Title;
|
|
}
|
|
POPUP_MSG_PARMS, *PPOPUP_MSG_PARMS;
|
|
|
|
|
|
//
|
|
// Private protos
|
|
//
|
|
|
|
DNS_STATUS
|
|
RslvrQueryToDnsServer(
|
|
OUT PDNS_RECORD * ppRecord,
|
|
IN PWSTR pwsName,
|
|
IN WORD wType,
|
|
IN DWORD Flags,
|
|
OUT PBOOL pfCacheNegativeResponse
|
|
);
|
|
|
|
BOOL
|
|
IsKnownTimedOutAdapter(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SetKnownTimedOutAdapter(
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
IsTimeToResetServerPriorities(
|
|
VOID
|
|
);
|
|
|
|
DWORD
|
|
PopupMessageThread(
|
|
IN PPOPUP_MSG_PARMS );
|
|
|
|
|
|
PDNS_RPC_CACHE_TABLE
|
|
CreateCacheTableEntry(
|
|
IN LPWSTR Name
|
|
);
|
|
|
|
VOID
|
|
FreeCacheTableEntryList(
|
|
IN PDNS_RPC_CACHE_TABLE pCacheTableList
|
|
);
|
|
|
|
BOOL
|
|
IsEmptyDnsResponse(
|
|
IN PDNS_RECORD
|
|
);
|
|
|
|
|
|
|
|
//
|
|
// Operations
|
|
//
|
|
|
|
DNS_STATUS
|
|
CRrReadCache(
|
|
IN DNS_RPC_HANDLE Reserved,
|
|
OUT PDNS_RPC_CACHE_TABLE * ppCacheTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/ // CRrReadCache
|
|
{
|
|
DNS_STATUS status = ERROR_SUCCESS;
|
|
PDNS_RPC_CACHE_TABLE pprevRpcEntry = NULL;
|
|
DWORD iter;
|
|
DWORD countEntries = 0;
|
|
|
|
#define MAX_RPC_CACHE_ENTRY_COUNT (300)
|
|
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
DNSDBG( RPC, ( "CRrReadCache\n" ));
|
|
|
|
if ( !ppCacheTable )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
*ppCacheTable = NULL;
|
|
|
|
DNSLOG_F1( "DNS Caching Resolver Service - CRrReadCache" );
|
|
|
|
if ( ClientThreadNotAllowedAccess() )
|
|
{
|
|
DNSLOG_F1( "CRrReadCache - ERROR_ACCESS_DENIED" );
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
LOCK_CACHE();
|
|
|
|
DNSLOG_F2( " Current number of entries in cache : %d",
|
|
g_EntryCount );
|
|
DNSLOG_F2( " Current number of RR sets in cache : %d",
|
|
g_RecordSetCount );
|
|
|
|
//
|
|
// Loop through all hash table slots looking for cache entries
|
|
// to return.
|
|
//
|
|
|
|
for ( iter = 0; iter < g_HashTableSize; iter++ )
|
|
{
|
|
PCACHE_ENTRY pentry = g_HashTable[iter];
|
|
DWORD iter2;
|
|
|
|
while ( pentry &&
|
|
countEntries < MAX_RPC_CACHE_ENTRY_COUNT )
|
|
{
|
|
PDNS_RPC_CACHE_TABLE prpcEntry;
|
|
|
|
prpcEntry = CreateCacheTableEntry( pentry->pName );
|
|
if ( ! prpcEntry )
|
|
{
|
|
// only failure is memory alloc
|
|
|
|
FreeCacheTableEntryList( *ppCacheTable );
|
|
*ppCacheTable = NULL;
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ErrorExit;
|
|
}
|
|
|
|
//
|
|
// insert new entry at end of current list
|
|
//
|
|
|
|
if ( pprevRpcEntry )
|
|
pprevRpcEntry->pNext = prpcEntry;
|
|
else
|
|
*ppCacheTable = prpcEntry;
|
|
|
|
pprevRpcEntry = prpcEntry;
|
|
|
|
countEntries++;
|
|
|
|
//
|
|
// fill in entry with current cached types
|
|
//
|
|
|
|
for ( iter2 = 0; iter2 < pentry->MaxCount; iter2++ )
|
|
{
|
|
PDNS_RECORD prr = pentry->Records[iter2];
|
|
WORD type;
|
|
|
|
if ( !prr )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// DCR -- goofy, just make sure the same and index (or limit?)
|
|
|
|
type = prr->wType;
|
|
|
|
if ( ! prpcEntry->Type1 )
|
|
prpcEntry->Type1 = type;
|
|
else if ( ! prpcEntry->Type2 )
|
|
prpcEntry->Type2 = type;
|
|
else
|
|
prpcEntry->Type3 = type;
|
|
}
|
|
|
|
pentry = pentry->pNext;
|
|
}
|
|
|
|
if ( countEntries > MAX_RPC_CACHE_ENTRY_COUNT )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ErrorExit:
|
|
|
|
UNLOCK_CACHE();
|
|
|
|
DNSLOG_F3( " CRrReadCache - Returning status : 0x%.8X\n\t%s",
|
|
status,
|
|
Dns_StatusString( status ) );
|
|
DNSLOG_F1( "" );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
CRrReadCacheEntry(
|
|
IN DNS_RPC_HANDLE Reserved,
|
|
IN LPWSTR pwsName,
|
|
IN WORD wType,
|
|
OUT PDNS_RECORD * ppRRSet
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/ // CRrReadCacheEntry
|
|
{
|
|
DNS_STATUS status;
|
|
PCACHE_ENTRY pentry;
|
|
PDNS_RECORD prr;
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
DNSLOG_F1( "DNS Caching Resolver Service - CRrReadCacheEntry" );
|
|
DNSLOG_F1( " Arguments:" );
|
|
DNSLOG_F2( " Name : %S", pwsName );
|
|
DNSLOG_F2( " Type : %d", wType );
|
|
DNSLOG_F1( "" );
|
|
|
|
DNSDBG( RPC, (
|
|
"\nCRrReadCacheEntry( %S, %d )\n",
|
|
pwsName,
|
|
wType ));
|
|
|
|
if ( !ppRRSet )
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
if ( ClientThreadNotAllowedAccess() )
|
|
{
|
|
DNSLOG_F1( "CRrReadCacheEntry - ERROR_ACCESS_DENIED" );
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
//
|
|
// find record in cache
|
|
// - copy if not NAME_ERROR or EMPTY
|
|
// - default to not-found error
|
|
// (DOES_NOT_EXIST error)
|
|
//
|
|
|
|
*ppRRSet = NULL;
|
|
status = DNS_ERROR_RECORD_DOES_NOT_EXIST;
|
|
|
|
Cache_GetRecordsForRpc(
|
|
ppRRSet,
|
|
& status,
|
|
pwsName,
|
|
wType,
|
|
0 // no screening flags
|
|
);
|
|
|
|
DNSLOG_F3( " CRrReadCacheEntry - Returning status : 0x%.8X\n\t%s",
|
|
status,
|
|
Dns_StatusString( status ) );
|
|
DNSLOG_F1( "" );
|
|
|
|
DNSDBG( RPC, (
|
|
"Leave CRrReadCacheEntry( %S, %d ) => %d\n\n",
|
|
pwsName,
|
|
wType,
|
|
status ));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
CRrGetHashTableStats(
|
|
IN DNS_RPC_HANDLE Reserved,
|
|
OUT LPDWORD pdwCacheHashTableSize,
|
|
OUT LPDWORD pdwCacheHashTableBucketSize,
|
|
OUT LPDWORD pdwNumberOfCacheEntries,
|
|
OUT LPDWORD pdwNumberOfRecords,
|
|
OUT LPDWORD pdwNumberOfExpiredRecords,
|
|
OUT PDNS_STATS_TABLE * ppStatsTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
|
|
--*/
|
|
{
|
|
PDNS_STATS_TABLE pprevRow = NULL;
|
|
PDWORD_LIST_ITEM pprevItem = NULL;
|
|
DWORD rowIter;
|
|
DWORD itemIter;
|
|
DWORD countExpiredRecords = 0;
|
|
DWORD status = ERROR_SUCCESS;
|
|
|
|
UNREFERENCED_PARAMETER(Reserved);
|
|
|
|
if ( !pdwCacheHashTableSize ||
|
|
!pdwCacheHashTableBucketSize ||
|
|
!pdwNumberOfCacheEntries ||
|
|
!pdwNumberOfRecords ||
|
|
!pdwNumberOfExpiredRecords ||
|
|
!ppStatsTable )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
DNSLOG_F1( "CRrGetHashTableStats" );
|
|
DNSDBG( RPC, ( "CRrGetHashTableStats\n" ));
|
|
|
|
if ( ClientThreadNotAllowedAccess() )
|
|
{
|
|
DNSLOG_F1( "CRrGetHashTableStats - ERROR_ACCESS_DENIED" );
|
|
return ERROR_ACCESS_DENIED;
|
|
}
|
|
|
|
LOCK_CACHE();
|
|
|
|
*pdwCacheHashTableSize = g_HashTableSize;
|
|
//*pdwCacheHashTableBucketSize = g_CacheHashTableBucketSize;
|
|
*pdwCacheHashTableBucketSize = 0;
|
|
*pdwNumberOfCacheEntries = g_EntryCount;
|
|
*pdwNumberOfRecords = g_RecordSetCount;
|
|
*pdwNumberOfExpiredRecords = 0;
|
|
|
|
//
|
|
// read entire hash table
|
|
//
|
|
|
|
for ( rowIter = 0;
|
|
rowIter < g_HashTableSize;
|
|
rowIter++ )
|
|
{
|
|
PCACHE_ENTRY pentry = g_HashTable[rowIter];
|
|
PDNS_STATS_TABLE pnewRow;
|
|
|
|
//
|
|
// create table for each new row
|
|
//
|
|
|
|
pnewRow = RPC_HEAP_ALLOC( sizeof(DNS_STATS_TABLE) );
|
|
if ( !pnewRow )
|
|
{
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
if ( rowIter == 0 )
|
|
*ppStatsTable = pnewRow;
|
|
else
|
|
pprevRow->pNext = pnewRow;
|
|
|
|
//
|
|
// fill in row data (if any)
|
|
//
|
|
|
|
while ( pentry )
|
|
{
|
|
PDWORD_LIST_ITEM pnewItem;
|
|
|
|
pnewItem = RPC_HEAP_ALLOC( sizeof( DWORD_LIST_ITEM ) );
|
|
if ( !pnewItem )
|
|
{
|
|
status = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Done;
|
|
}
|
|
|
|
for ( itemIter = 0;
|
|
itemIter < pentry->MaxCount;
|
|
itemIter++ )
|
|
{
|
|
PDNS_RECORD prr = pentry->Records[itemIter];
|
|
if ( prr )
|
|
{
|
|
pnewItem->Value1++;
|
|
|
|
if ( !Cache_IsRecordTtlValid( prr ) )
|
|
{
|
|
pnewItem->Value2++;
|
|
countExpiredRecords++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !pnewRow->pListItem )
|
|
pnewRow->pListItem = pnewItem;
|
|
else
|
|
pprevItem->pNext = pnewItem;
|
|
|
|
pprevItem = pnewItem;
|
|
pentry = pentry->pNext;
|
|
}
|
|
|
|
pprevRow = pnewRow;
|
|
}
|
|
|
|
Done:
|
|
|
|
UNLOCK_CACHE();
|
|
*pdwNumberOfExpiredRecords = countExpiredRecords;
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsKnownNetFailure(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if we are in known net failure window.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if in known net failure
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOL flag = FALSE;
|
|
|
|
DNSDBG( TRACE, ( "IsKnownNetFailure()\n" ));
|
|
|
|
LOCK_NET_FAILURE();
|
|
|
|
if ( g_NetFailureStatus )
|
|
{
|
|
if ( g_NetFailureTime < Dns_GetCurrentTimeInSeconds() )
|
|
{
|
|
g_NetFailureTime = 0;
|
|
g_NetFailureStatus = ERROR_SUCCESS;
|
|
flag = FALSE;
|
|
}
|
|
else
|
|
{
|
|
SetLastError( g_NetFailureStatus );
|
|
flag = TRUE;
|
|
}
|
|
}
|
|
|
|
UNLOCK_NET_FAILURE();
|
|
|
|
return flag;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SetKnownNetFailure(
|
|
IN DNS_STATUS Status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Set cause of net failure.
|
|
|
|
Arguments:
|
|
|
|
Status -- status code for cause of net failure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LPSTR DnsString = NULL;
|
|
LPWSTR InsertStrings[3];
|
|
WCHAR String1[25];
|
|
WCHAR String2[256];
|
|
WCHAR String3[25];
|
|
|
|
DNSDBG( TRACE, ( "SetKnownNetFailure()\n" ));
|
|
|
|
//
|
|
// don't indicate failure during boot
|
|
//
|
|
|
|
if ( Dns_GetCurrentTimeInSeconds() < THREE_MINUTES_FROM_SYSTEM_BOOT )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !g_LocalAddrArray || g_NetFailureCacheTime == 0 )
|
|
{
|
|
//
|
|
// We are in a no-net configuration, there is no need
|
|
// to display the pop-up message. No point warning
|
|
// of DNS configuration problems when the system is
|
|
// off the net.
|
|
// - or -
|
|
// We are on a NT server, and therefore don't do poor network
|
|
// performance caching.
|
|
//
|
|
return;
|
|
}
|
|
|
|
|
|
LOCK_NET_FAILURE();
|
|
|
|
g_NetFailureTime = Dns_GetCurrentTimeInSeconds() + g_NetFailureCacheTime;
|
|
g_NetFailureStatus = Status;
|
|
|
|
wsprintfW( String1, L"0x%.8X", Status );
|
|
|
|
DnsString = DnsStatusString( Status );
|
|
|
|
if ( DnsString )
|
|
{
|
|
Dns_StringCopy( (PBYTE) String2,
|
|
NULL,
|
|
(PCHAR) DnsString,
|
|
(WORD) strlen( DnsString ),
|
|
DnsCharSetAnsi,
|
|
DnsCharSetUnicode );
|
|
//
|
|
// No need to free this since the string is just a pointer
|
|
// to a global table entry.
|
|
//
|
|
// FREE_HEAP( DnsString );
|
|
}
|
|
else
|
|
{
|
|
wsprintfW( String2, L"<?>" );
|
|
}
|
|
|
|
wsprintfW( String3, L"%d", g_NetFailureCacheTime );
|
|
|
|
if ( g_MessagePopupStrikes < 3 )
|
|
{
|
|
g_MessagePopupStrikes++;
|
|
}
|
|
else
|
|
{
|
|
if ( Status != g_PreviousNetFailureStatus )
|
|
{
|
|
//
|
|
// DCR_PERF: should remove logging from inside lock
|
|
//
|
|
|
|
InsertStrings[0] = String1;
|
|
InsertStrings[1] = String2;
|
|
InsertStrings[2] = String3;
|
|
|
|
ResolverLogEvent(
|
|
EVENT_DNS_CACHE_NETWORK_PERF_WARNING,
|
|
EVENTLOG_WARNING_TYPE,
|
|
3,
|
|
InsertStrings,
|
|
Status );
|
|
g_PreviousNetFailureStatus = Status;
|
|
}
|
|
|
|
g_MessagePopupStrikes = 0;
|
|
}
|
|
|
|
UNLOCK_NET_FAILURE();
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsKnownTimedOutAdapter(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine if timed out adapter exists.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
TRUE if timed out adapter
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOL flag = FALSE;
|
|
|
|
DNSDBG( TRACE, ( "IsKnownTimedOutAdapter()\n" ));
|
|
|
|
//
|
|
// DCR: don't really need lock for this?
|
|
// - could check if lock taken?
|
|
// but if beat it -- so what
|
|
//
|
|
|
|
LOCK_NET_FAILURE();
|
|
|
|
if ( g_fTimedOutAdapter )
|
|
{
|
|
if ( g_TimedOutAdapterTime < Dns_GetCurrentTimeInSeconds() )
|
|
{
|
|
DNSLOG_F1( " Timed out adapter cache expired, resseting adapter!" );
|
|
g_TimedOutAdapterTime = 0;
|
|
g_fTimedOutAdapter = FALSE;
|
|
flag = FALSE;
|
|
}
|
|
else
|
|
{
|
|
flag = TRUE;
|
|
}
|
|
}
|
|
|
|
UNLOCK_NET_FAILURE();
|
|
|
|
return flag;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SetKnownTimedOutAdapter(
|
|
VOID
|
|
)
|
|
{
|
|
DNSDBG( TRACE, ( "SetKnownTimedOutAdapter()\n" ));
|
|
|
|
if ( Dns_GetCurrentTimeInSeconds() < THREE_MINUTES_FROM_SYSTEM_BOOT )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( !g_LocalAddrArray )
|
|
{
|
|
//
|
|
// We are in a no-net configuration, there is no need
|
|
// to display the pop-up message. No point warning
|
|
// of DNS configuration problems when the system is
|
|
// off the net.
|
|
//
|
|
return;
|
|
}
|
|
|
|
DNSLOG_F1( " Detected a timed out adapter, disabling it for a little while" );
|
|
|
|
LOCK_NET_FAILURE();
|
|
|
|
g_TimedOutAdapterTime = Dns_GetCurrentTimeInSeconds() +
|
|
g_AdapterTimeoutLimit;
|
|
|
|
g_fTimedOutAdapter = TRUE;
|
|
|
|
UNLOCK_NET_FAILURE();
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
PopupMessageThread(
|
|
IN OUT PPOPUP_MSG_PARMS MsgParms
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Popup a message box with error.
|
|
|
|
Arguments:
|
|
|
|
MsgParms -- popup message parameters
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
MessageBoxW(
|
|
NULL,
|
|
MsgParms->Message,
|
|
MsgParms->Title,
|
|
MB_SERVICE_NOTIFICATION | MB_ICONWARNING | MB_OK );
|
|
|
|
GENERAL_HEAP_FREE( MsgParms->Message );
|
|
GENERAL_HEAP_FREE( MsgParms->Title );
|
|
GENERAL_HEAP_FREE( MsgParms );
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ClientThreadNotAllowedAccess(
|
|
VOID
|
|
)
|
|
{
|
|
#if 0
|
|
//
|
|
// DCR: should probably access check only for flush cache or
|
|
// delete entry
|
|
//
|
|
|
|
//
|
|
// DCR: - This idea of adding a security check for
|
|
// DNS RPC API is really debatable. The data
|
|
// maintained by the DNS Caching Resolver is definately
|
|
// not private. Since the cache mimicks the DNS protocol
|
|
// as a non-handle based access to public information,
|
|
// it would require an access check for every interface
|
|
// and for every call. Doing this would required a context
|
|
// switch into kernel mode to perform the check. This is
|
|
// a lot of overhead just to protect an API that provides
|
|
// access to widely available information. After all, the
|
|
// cache is supposed to improve name resolution performance!
|
|
//
|
|
// Below is the start of some code to implement an access
|
|
// check, though it sounds like I should call the Win32
|
|
// security function AccessCheck() and create a DNS cache
|
|
// SID to compare the desired access of the client thread
|
|
// against. This is not finished and I don't intend to
|
|
// try finish it.
|
|
//
|
|
|
|
GENERIC_MAPPING DNSAccessMapping = {
|
|
STANDARD_RIGHTS_READ,
|
|
STANDARD_RIGHTS_WRITE,
|
|
STANDARD_RIGHTS_EXECUTE
|
|
};
|
|
|
|
HANDLE hThread = GetCurrentThread();
|
|
DWORD dwGrantedAccess;
|
|
BOOL Result;
|
|
|
|
if ( RpcImpersonateClient(NULL) )
|
|
return TRUE;
|
|
|
|
hThread = GetCurrentThread();
|
|
|
|
if ( !hThread )
|
|
{
|
|
RpcRevertToSelf();
|
|
return TRUE;
|
|
}
|
|
|
|
if ( OpenThreadToken( hThread,
|
|
TOKEN_QUERY,
|
|
FALSE,
|
|
&hToken ) )
|
|
{
|
|
if ( AccessCheck( pSD,
|
|
hToken,
|
|
STANDARD_RIGHTS_WRITE,
|
|
&DNSAccessMapping,
|
|
pPS,
|
|
sizeof( *pPS ),
|
|
&dwGrantedAccess,
|
|
&Result );
|
|
}
|
|
|
|
CloseHandle( hThread );
|
|
|
|
RpcRevertToSelf();
|
|
|
|
if ( Result )
|
|
return FALSE;
|
|
else
|
|
return TRUE;
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
PDNS_RPC_CACHE_TABLE
|
|
CreateCacheTableEntry(
|
|
IN LPWSTR pwsName
|
|
)
|
|
{
|
|
PDNS_RPC_CACHE_TABLE prpcEntry = NULL;
|
|
|
|
if ( ! pwsName )
|
|
return NULL;
|
|
|
|
prpcEntry = (PDNS_RPC_CACHE_TABLE)
|
|
RPC_HEAP_ALLOC_ZERO( sizeof(DNS_RPC_CACHE_TABLE) );
|
|
|
|
if ( prpcEntry == NULL )
|
|
return NULL;
|
|
|
|
prpcEntry->Name = RPC_HEAP_ALLOC( sizeof(WCHAR) * (wcslen(pwsName) + 1) );
|
|
if ( ! prpcEntry->Name )
|
|
{
|
|
RPC_HEAP_FREE( prpcEntry );
|
|
return NULL;
|
|
}
|
|
|
|
wcscpy( prpcEntry->Name, pwsName );
|
|
|
|
return prpcEntry;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
FreeCacheTableEntryList(
|
|
IN PDNS_RPC_CACHE_TABLE pCacheTableList )
|
|
{
|
|
while ( pCacheTableList )
|
|
{
|
|
PDNS_RPC_CACHE_TABLE pNext = pCacheTableList->pNext;
|
|
|
|
if ( pCacheTableList->Name )
|
|
{
|
|
RPC_HEAP_FREE( pCacheTableList->Name );
|
|
pCacheTableList->Name = NULL;
|
|
}
|
|
|
|
RPC_HEAP_FREE( pCacheTableList );
|
|
|
|
pCacheTableList = pNext;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
IsEmptyDnsResponse(
|
|
IN PDNS_RECORD pRecord
|
|
)
|
|
{
|
|
//
|
|
// DCR_FIX: should be dnslib utility
|
|
//
|
|
// DCR_FIX: should distinguish referral and no-records
|
|
//
|
|
|
|
PDNS_RECORD pTempRecord = pRecord;
|
|
BOOL fEmpty = TRUE;
|
|
|
|
while ( pTempRecord )
|
|
{
|
|
if ( pTempRecord->Flags.S.Section == DNSREC_ANSWER )
|
|
{
|
|
fEmpty = FALSE;
|
|
break;
|
|
}
|
|
pTempRecord = pTempRecord->pNext;
|
|
}
|
|
|
|
return fEmpty;
|
|
}
|
|
|
|
|
|
DNS_STATUS
|
|
CRrUpdateTest(
|
|
IN DNS_RPC_HANDLE Reserved,
|
|
IN PWSTR pwsName,
|
|
IN DWORD fOptions,
|
|
IN IP_ADDRESS ServerIp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Do update test for existing record.
|
|
|
|
DCR: need UpdateTest() IPv6 capable
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
ErrorCode from update attempt.
|
|
|
|
--*/
|
|
{
|
|
DNS_STATUS status = ERROR_SUCCESS;
|
|
DNS_RECORD record;
|
|
DWORD flags = fOptions;
|
|
PSTR pnameTemp = NULL;
|
|
PDNS_NETINFO pnetInfo = NULL;
|
|
IP_ARRAY serverIpArray;
|
|
PIP_ARRAY pserverIpArray = NULL;
|
|
|
|
|
|
DNSLOG_F1( "DNS Caching Resolver Service - CRrUpdateTest" );
|
|
DNSDBG( RPC, ( "\nCRrUpdateTest()\n" ));
|
|
|
|
//
|
|
// Validate arguments
|
|
//
|
|
|
|
if ( !pwsName || !ServerIp )
|
|
{
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// make UTF8 name and FAZ
|
|
//
|
|
// DCR: not clear why all this work isn't just done in update API
|
|
//
|
|
|
|
pnameTemp = Dns_NameCopyAllocate(
|
|
(PCHAR) pwsName,
|
|
0,
|
|
DnsCharSetUnicode,
|
|
DnsCharSetUtf8 );
|
|
if ( ! pnameTemp )
|
|
{
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
serverIpArray.AddrCount = 1;
|
|
serverIpArray.AddrArray[0] = ServerIp;
|
|
pserverIpArray = &serverIpArray;
|
|
|
|
status = Dns_FindAuthoritativeZoneLib(
|
|
(PDNS_NAME) pnameTemp,
|
|
0,
|
|
pserverIpArray,
|
|
&pnetInfo );
|
|
|
|
if ( status != NO_ERROR )
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// build update prereq "nothing exists" record
|
|
//
|
|
|
|
RtlZeroMemory( &record, sizeof(DNS_RECORD) );
|
|
record.pName = (PDNS_NAME) pnameTemp;
|
|
record.wType = DNS_TYPE_ANY;
|
|
record.wDataLength = 0;
|
|
record.Flags.DW = DNSREC_PREREQ | DNSREC_NOEXIST;
|
|
|
|
//
|
|
// update
|
|
//
|
|
|
|
status = Dns_UpdateLib(
|
|
&record,
|
|
0,
|
|
pnetInfo,
|
|
NULL,
|
|
NULL );
|
|
|
|
Cleanup:
|
|
|
|
Dns_Free( pnameTemp );
|
|
|
|
NetInfo_Free( pnetInfo );
|
|
|
|
DNSDBG( RPC, (
|
|
"Leave CRrUpdateTest() => %d\n\n",
|
|
status ));
|
|
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// End remote.c
|
|
//
|