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.
 
 
 
 
 
 

1718 lines
51 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
stub.c
Abstract:
Domain Name System (DNS) Server -- Admin Client API
Client stubs for DNS API.
These are stubs for NT5+ API. NT4 API stubs are in nt4stub.c.
Author:
Jim Gilroy (jamesg) April 1997
Environment:
User Mode - Win32
Revision History:
--*/
#include "dnsclip.h"
#if DBG
#include "rpcasync.h"
#endif
//
// For versioning, we use a simple state machine in each function's
// RPC exception block to try the new RPC call then the old RPC call.
// If there is any RPC error, retry a downlevel operation.
//
// This macro'ing is a bit overkill, but each RPC interface wrapper
// needs this retry logic.
//
#define DNS_RPC_RETRY_STATE() iDnsRpcRetryState
#define DECLARE_DNS_RPC_RETRY_LABEL() DnsRpcRetryLabel:
#define DECLARE_DNS_RPC_RETRY_STATE( status ) \
INT DNS_RPC_RETRY_STATE() = 0; \
status = dnsrpcInitializeTls()
// Test return code to see if we need to retry for W2K remote RPC server.
#define ADVANCE_DNS_RPC_RETRY_STATE( dwStatus ) \
if ( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW && \
dwStatus != RPC_S_SEC_PKG_ERROR && \
( dwStatus == ERROR_SUCCESS || \
dwStatus == RPC_S_SERVER_UNAVAILABLE || \
dwStatus < RPC_S_INVALID_STRING_BINDING || \
dwStatus > RPC_X_BAD_STUB_DATA ) ) \
DNS_RPC_RETRY_STATE() = DNS_RPC_TRY_DONE; \
else \
{ \
dnsrpcSetW2KBindFlag( TRUE ); \
++DNS_RPC_RETRY_STATE(); \
}
#define TEST_DNS_RPC_RETRY() \
if ( DNS_RPC_RETRY_STATE() < DNS_RPC_TRY_DONE ) { goto DnsRpcRetryLabel; }
#define ASSERT_DNS_RPC_RETRY_STATE_VALID() \
ASSERT( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW || \
DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_OLD )
#define DNS_RPC_TRY_NEW 0
#define DNS_RPC_TRY_OLD 1
#define DNS_RPC_TRY_DONE 2
//
// This macro is a safety helper for use in DnsRpc_ConvertToCurrent.
//
// If header definitions change, DnsRpc_ConvertToCurrent can
// start doing wacky things. Using memcpy instead of individual
// assignments saves instructions but is potentially dangerous if
// headers change and this function is not updated. Add ASSERTS
// where possible to try and catch header changes that have not
// been accounted for here. A general principal is that a structure
// may grow but not shrink in size between versions.
//
#if DBG
#define DNS_ASSERT_CURRENT_LARGER( structName ) \
ASSERT( sizeof( DNS_RPC_##structName##_DOTNET ) >= \
sizeof( DNS_RPC_##structName##_W2K ) );
#define DNS_ASSERT_RPC_STRUCTS_ARE_SANE() \
{ \
static LONG finit = 0; \
\
if ( InterlockedIncrement( &finit ) != 1 ) \
{ \
goto DoneDbgAsserts; \
} \
\
DNS_ASSERT_CURRENT_LARGER( SERVER_INFO ); \
DNS_ASSERT_CURRENT_LARGER( FORWARDERS ); \
DNS_ASSERT_CURRENT_LARGER( ZONE ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_INFO ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_SECONDARIES ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_DATABASE ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_TYPE_RESET ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_CREATE_INFO ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_LIST ); \
DNS_ASSERT_CURRENT_LARGER( SERVER_INFO ); \
DNS_ASSERT_CURRENT_LARGER( FORWARDERS ); \
DNS_ASSERT_CURRENT_LARGER( ZONE ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_SECONDARIES ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_DATABASE ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_TYPE_RESET ); \
DNS_ASSERT_CURRENT_LARGER( ZONE_LIST ); \
\
DoneDbgAsserts: ; \
}
#else
#define DNS_ASSERT_RPC_STRUCTS_ARE_SANE()
#endif // DBG
DWORD g_bAttemptW2KRPCBindTlsIndex = TLS_OUT_OF_INDEXES;
DNS_STATUS
dnsrpcInitializeTls(
VOID
)
/*++
Routine Description:
The W2K RPC bind global retry flag is stored in thread local
storage. Each stub function must make certain that the TLS index
is allocated before calling any RPC interface. Unfortunately there
is no initialization function called by clients of DNSRPC.LIB
where this can be done.
NOTE: the TLS block is never freed. There is no convenient place
to clean it up so for now just let it persist until process
termination. This is harmless and is not a leak.
Arguments:
Return Value:
On failure, there was a TLS error - likely too many TLS indices
have been allocated in this process.
--*/
{
static LONG dnsrpcTlsInitialized = 0;
DWORD tlsIndex;
DNS_STATUS status = ERROR_SUCCESS;
//
// Quick-check: already initialized?
//
if ( dnsrpcTlsInitialized )
{
goto Done;
}
//
// Safe-check for initialization. If two threads attempt to initialize
// at the same time the quick-check above may pass both. The safe check
// will ensure that only one thread will actually perform initialization.
//
if ( InterlockedIncrement( &dnsrpcTlsInitialized ) != 1 )
{
InterlockedDecrement( &dnsrpcTlsInitialized );
goto Done;
}
//
// Initialize the TLS index for the DNSRPC W2K retry flag.
//
tlsIndex = TlsAlloc();
ASSERT( tlsIndex != TLS_OUT_OF_INDEXES );
if ( tlsIndex == TLS_OUT_OF_INDEXES )
{
status = GetLastError();
goto Done;
}
g_bAttemptW2KRPCBindTlsIndex = tlsIndex;
//
// Provide initial flag value.
//
dnsrpcSetW2KBindFlag( FALSE );
Done:
return status;
} // dnsrpcInitializeTls
VOID
dnsrpcSetW2KBindFlag(
BOOL newFlagValue
)
/*++
Routine Description:
Sets the W2K bind retry flag in thread local storage.
Arguments:
newFlagValue -- new flag value to be stored in TLS
Return Value:
--*/
{
DWORD tlsIndex = g_bAttemptW2KRPCBindTlsIndex;
ASSERT( tlsIndex != TLS_OUT_OF_INDEXES );
if ( tlsIndex != TLS_OUT_OF_INDEXES )
{
TlsSetValue( tlsIndex, ( LPVOID ) ( DWORD_PTR ) newFlagValue );
}
} // dnsrpcSetW2KBindFlag
BOOL
dnsrpcGetW2KBindFlag(
VOID
)
/*++
Routine Description:
Gets the W2K bind retry flag from thread local storage.
Arguments:
Return Value:
The current value of this thread's W2K bind retry flag.
--*/
{
DWORD tlsIndex = g_bAttemptW2KRPCBindTlsIndex;
ASSERT( tlsIndex != TLS_OUT_OF_INDEXES );
if ( tlsIndex == TLS_OUT_OF_INDEXES )
{
return FALSE;
}
else
{
return ( BOOL ) ( DWORD_PTR ) TlsGetValue( tlsIndex );
}
} // dnsrpcSetW2KBindFlag
VOID
printExtendedRpcErrorInfo(
DNS_STATUS externalStatus
)
/*++
Routine Description:
Prints extended RPC error information to console.
Arguments:
Return Value:
--*/
{
#if DBG
DBG_FN( "RpcError" )
RPC_STATUS status;
RPC_ERROR_ENUM_HANDLE enumHandle;
if ( externalStatus == ERROR_SUCCESS )
{
return;
}
status = RpcErrorStartEnumeration( &enumHandle );
if ( status != RPC_S_OK )
{
printf( "%s: error %d retrieving RPC error information\n", fn, status );
}
else
{
RPC_EXTENDED_ERROR_INFO errorInfo;
int records;
BOOL result;
BOOL copyStrings = TRUE;
BOOL fuseFileTime = TRUE;
SYSTEMTIME * systemTimeToUse;
SYSTEMTIME systemTimeBuffer;
while ( status == RPC_S_OK )
{
errorInfo.Version = RPC_EEINFO_VERSION;
errorInfo.Flags = 0;
errorInfo.NumberOfParameters = 4;
if ( fuseFileTime )
{
errorInfo.Flags |= EEInfoUseFileTime;
}
status = RpcErrorGetNextRecord( &enumHandle, copyStrings, &errorInfo );
if ( status == RPC_S_ENTRY_NOT_FOUND )
{
break;
}
else if ( status != RPC_S_OK )
{
printf( "%s: error %d during error info enumeration\n", fn, status );
break;
}
else
{
int i;
if ( errorInfo.ComputerName )
{
printf( "%s: ComputerName %S\n", fn, errorInfo.ComputerName );
if ( copyStrings )
{
result = HeapFree( GetProcessHeap(), 0, errorInfo.ComputerName );
ASSERT( result );
}
}
printf( "ProcessID is %d\n", errorInfo.ProcessID );
if ( fuseFileTime )
{
result = FileTimeToSystemTime(
&errorInfo.u.FileTime,
&systemTimeBuffer);
ASSERT( result );
systemTimeToUse = &systemTimeBuffer;
}
else
{
systemTimeToUse = &errorInfo.u.SystemTime;
}
printf(
"System Time is: %d/%d/%d %d:%d:%d:%d\n",
systemTimeToUse->wMonth,
systemTimeToUse->wDay,
systemTimeToUse->wYear,
systemTimeToUse->wHour,
systemTimeToUse->wMinute,
systemTimeToUse->wSecond,
systemTimeToUse->wMilliseconds );
printf( "Generating component is %d\n", errorInfo.GeneratingComponent );
printf( "Status is %d\n", errorInfo.Status );
printf( "Detection location is %d\n", ( int ) errorInfo.DetectionLocation );
printf( "Flags is %d\n", errorInfo.Flags );
printf( "NumberOfParameters is %d\n", errorInfo.NumberOfParameters );
for ( i = 0; i < errorInfo.NumberOfParameters; ++i )
{
switch( errorInfo.Parameters[i].ParameterType )
{
case eeptAnsiString:
printf( "Ansi string: %s\n",
errorInfo.Parameters[i].u.AnsiString );
if ( copyStrings )
{
result = HeapFree( GetProcessHeap(),
0,
errorInfo.Parameters[i].u.AnsiString );
ASSERT( result );
}
break;
case eeptUnicodeString:
printf( "Unicode string: %S\n",
errorInfo.Parameters[i].u.UnicodeString );
if ( copyStrings )
{
result = HeapFree(
GetProcessHeap(),
0,
errorInfo.Parameters[i].u.UnicodeString );
ASSERT( result );
}
break;
case eeptLongVal:
printf( "Long val: %d\n", errorInfo.Parameters[i].u.LVal );
break;
case eeptShortVal:
printf( "Short val: %d\n", ( int ) errorInfo.Parameters[i].u.SVal );
break;
case eeptPointerVal:
printf( "Pointer val: %d\n", errorInfo.Parameters[i].u.PVal );
break;
case eeptNone:
printf( "Truncated\n" );
break;
default:
printf( "Invalid type: %d\n", errorInfo.Parameters[i].ParameterType );
break;
}
}
}
}
RpcErrorEndEnumeration( &enumHandle );
}
#endif
} // printExtendedRpcErrorInfo
DNS_STATUS
DNS_API_FUNCTION
DnsRpc_ConvertToCurrent(
IN PDWORD pdwTypeId, IN OUT
IN PVOID * ppData IN OUT
)
/*++
Routine Description:
Takes any DNS RPC structure as input and if necessary fabricates
the latest revision of that structure from the members of the input
structure.
If a new structure is allocated, the old one is freed and the pointer
value at ppData is replaced. Allocated points within the old struct
will be freed or copied to the new struct. Basically, the client
does not have to worry about freeing any part of the old struct. When
he's done with the new struct he has to free it and it's members, as
usual.
There are two main uses of this function:
- If an old client sends the DNS server an input structure, such as
ZONE_CREATE, the new DNS server can use this function to update
the structure so that it can be processed.
- If an old server sends the DNS RPC client an output structure, such
as SERVER_INFO, the new DNS RPC client can use this function to
update the structure so that it can be processed.
Arguments:
pdwTypeId - type ID of object pointed to by ppData, value may be
changed to type ID of new object at ppData
ppData - pointer to object, pointer may be replaced by a pointer to
a newly allocated, completed different structure as required
Return Value:
ERROR_SUCCESS or error code. If return code is not ERROR_SUCCESS, there
has been some kind of fatal error. Assume data invalid in this case.
--*/
{
DBG_FN( "DnsRpc_ConvertToCurrent" )
DNS_STATUS status = ERROR_SUCCESS;
DWORD dwtypeIn = -1;
PVOID pdataIn = NULL;
DWORD dwtypeOut = -1;
PVOID pdataOut = NULL;
DWORD i;
if ( !pdwTypeId || !ppData )
{
ASSERT( pdwTypeId && ppData );
status = ERROR_INVALID_DATA;
goto NoTranslation;
}
//
// Shortcuts: do not translate NULL or certain common types.
//
if ( *pdwTypeId < DNSSRV_TYPEID_SERVER_INFO_W2K || *ppData == NULL )
{
goto NoTranslation;
}
dwtypeOut = dwtypeIn = *pdwTypeId;
pdataOut = pdataIn = *ppData;
DNS_ASSERT_RPC_STRUCTS_ARE_SANE();
//
// Handy macros to make allocating the differently sized structs easy.
//
#define ALLOCATE_RPC_BYTES( ptr, byteCount ) \
ptr = MIDL_user_allocate( byteCount ); \
if ( ptr == NULL ) \
{ \
status = DNS_ERROR_NO_MEMORY; \
goto Done; \
} \
RtlZeroMemory( ptr, byteCount );
#define ALLOCATE_RPC_STRUCT( ptr, structType ) \
ALLOCATE_RPC_BYTES( ptr, sizeof( structType ) );
#define DNS_DOTNET_VERSION_SIZE ( 2 * sizeof( DWORD ) )
//
// Giant switch statement of all types that are no longer current.
//
// Add to this switch as we create more versions of types. The idea
// is to convert any structure from an old server to the
// corresponding current version so that the RPC client doesn't
// have to worry about multiple versions of the structures.
//
switch ( dwtypeIn )
{
case DNSSRV_TYPEID_SERVER_INFO_W2K:
//
// Do a member-by-member copy so .NET is not contrained
// by the W2K structure layout.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_SERVER_INFO_DOTNET );
#define MEMBERCOPY( _Member ) \
( ( PDNS_RPC_SERVER_INFO_DOTNET ) pdataOut )->_Member = \
( ( PDNS_RPC_SERVER_INFO_W2K ) pdataIn )->_Member
MEMBERCOPY( dwVersion );
MEMBERCOPY( fAdminConfigured );
MEMBERCOPY( fAllowUpdate );
MEMBERCOPY( fDsAvailable );
MEMBERCOPY( pszServerName );
MEMBERCOPY( pszDsContainer );
MEMBERCOPY( aipServerAddrs );
MEMBERCOPY( aipListenAddrs );
MEMBERCOPY( aipForwarders );
MEMBERCOPY( dwLogLevel );
MEMBERCOPY( dwDebugLevel );
MEMBERCOPY( dwForwardTimeout );
MEMBERCOPY( dwRpcProtocol );
MEMBERCOPY( dwNameCheckFlag );
MEMBERCOPY( cAddressAnswerLimit );
MEMBERCOPY( dwRecursionTimeout );
MEMBERCOPY( dwMaxCacheTtl );
MEMBERCOPY( dwDsPollingInterval );
MEMBERCOPY( dwScavengingInterval );
MEMBERCOPY( dwDefaultRefreshInterval );
MEMBERCOPY( dwDefaultNoRefreshInterval );
MEMBERCOPY( fAutoReverseZones );
MEMBERCOPY( fAutoCacheUpdate );
MEMBERCOPY( fSlave );
MEMBERCOPY( fForwardDelegations );
MEMBERCOPY( fNoRecursion );
MEMBERCOPY( fSecureResponses );
MEMBERCOPY( fRoundRobin );
MEMBERCOPY( fLocalNetPriority );
MEMBERCOPY( fBindSecondaries );
MEMBERCOPY( fWriteAuthorityNs );
MEMBERCOPY( fStrictFileParsing );
MEMBERCOPY( fLooseWildcarding );
MEMBERCOPY( fDefaultAgingState );
MEMBERCOPY( dwMaxCacheTtl );
MEMBERCOPY( dwMaxCacheTtl );
dwtypeOut = DNSSRV_TYPEID_SERVER_INFO;
break;
case DNSSRV_TYPEID_FORWARDERS_W2K:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_FORWARDERS_DOTNET );
RtlCopyMemory(
( PBYTE ) pdataOut + DNS_DOTNET_VERSION_SIZE,
pdataIn,
sizeof( DNS_RPC_FORWARDERS_W2K ) );
( ( PDNS_RPC_FORWARDERS_DOTNET ) pdataOut )->
dwRpcStructureVersion = DNS_RPC_FORWARDERS_VER;
dwtypeOut = DNSSRV_TYPEID_FORWARDERS;
break;
case DNSSRV_TYPEID_ZONE_W2K:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_DOTNET );
RtlCopyMemory(
( PBYTE ) pdataOut + DNS_DOTNET_VERSION_SIZE,
pdataIn,
sizeof( DNS_RPC_ZONE_W2K ) );
( ( PDNS_RPC_ZONE_DOTNET ) pdataOut )->
dwRpcStructureVersion = DNS_RPC_ZONE_VER;
dwtypeOut = DNSSRV_TYPEID_ZONE;
break;
case DNSSRV_TYPEID_ZONE_INFO_W2K:
//
// .NET structure is larger and has new fields for
// forwarder zones, stub zones, directory partitions, etc.
// The structures are identical up to the beginning of
// the reserved DWORDs at the end of the W2K structure.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_INFO_DOTNET );
RtlZeroMemory( pdataOut, sizeof( DNS_RPC_ZONE_INFO_DOTNET ) );
RtlCopyMemory(
( PBYTE ) pdataOut + DNS_DOTNET_VERSION_SIZE,
pdataIn,
sizeof( DNS_RPC_ZONE_INFO_W2K ) );
( ( PDNS_RPC_ZONE_INFO_DOTNET ) pdataOut )->
dwRpcStructureVersion = DNS_RPC_ZONE_VER;
dwtypeOut = DNSSRV_TYPEID_ZONE_INFO;
break;
case DNSSRV_TYPEID_ZONE_SECONDARIES_W2K:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_SECONDARIES_DOTNET );
RtlCopyMemory(
( PBYTE ) pdataOut + DNS_DOTNET_VERSION_SIZE,
pdataIn,
sizeof( DNS_RPC_ZONE_SECONDARIES_W2K ) );
( ( PDNS_RPC_ZONE_SECONDARIES_DOTNET ) pdataOut )->
dwRpcStructureVersion = DNS_RPC_ZONE_SECONDARIES_VER;
dwtypeOut = DNSSRV_TYPEID_ZONE_SECONDARIES;
break;
case DNSSRV_TYPEID_ZONE_DATABASE_W2K:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_DATABASE_DOTNET );
RtlCopyMemory(
( PBYTE ) pdataOut + DNS_DOTNET_VERSION_SIZE,
pdataIn,
sizeof( DNS_RPC_ZONE_DATABASE_W2K ) );
( ( PDNS_RPC_ZONE_DATABASE_DOTNET ) pdataOut )->
dwRpcStructureVersion = DNS_RPC_ZONE_DATABASE_VER;
dwtypeOut = DNSSRV_TYPEID_ZONE_DATABASE;
break;
case DNSSRV_TYPEID_ZONE_TYPE_RESET_W2K:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_TYPE_RESET_DOTNET );
RtlCopyMemory(
( PBYTE ) pdataOut + DNS_DOTNET_VERSION_SIZE,
pdataIn,
sizeof( DNS_RPC_ZONE_TYPE_RESET_W2K ) );
( ( PDNS_RPC_ZONE_TYPE_RESET_DOTNET ) pdataOut )->
dwRpcStructureVersion = DNS_RPC_ZONE_TYPE_RESET_VER;
dwtypeOut = DNSSRV_TYPEID_ZONE_TYPE_RESET;
break;
case DNSSRV_TYPEID_ZONE_CREATE_W2K:
//
// Structures are identical except for dwRpcStructureVersion
// and some usage in .NET of reserved W2K fields. No
// need to be concerned about the newly used reserved, they
// will be NULL in the W2K structure.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_CREATE_INFO_DOTNET );
RtlCopyMemory(
( PBYTE ) pdataOut + DNS_DOTNET_VERSION_SIZE,
pdataIn,
sizeof( DNS_RPC_ZONE_CREATE_INFO_W2K ) );
( ( PDNS_RPC_ZONE_CREATE_INFO_DOTNET ) pdataOut )->
dwRpcStructureVersion = DNS_RPC_ZONE_CREATE_INFO_VER;
dwtypeOut = DNSSRV_TYPEID_ZONE_CREATE;
break;
case DNSSRV_TYPEID_ZONE_LIST_W2K:
{
DWORD dwzoneCount;
DWORD dwzonePtrCount;
PDNS_RPC_ZONE_LIST_DOTNET pzonelistDotNet;
PDNS_RPC_ZONE_LIST_W2K pzonelistW2K;
//
// Structures are identical except for dwRpcStructureVersion.
// Note: there is always at least one pointer, even if the
// zone count is zero.
//
pzonelistW2K = ( PDNS_RPC_ZONE_LIST_W2K ) pdataIn;
dwzoneCount = dwzonePtrCount = pzonelistW2K->dwZoneCount;
if ( dwzonePtrCount > 0 )
{
--dwzonePtrCount; // num ptrs after ZONE_LIST struct
}
ALLOCATE_RPC_BYTES(
pzonelistDotNet,
sizeof( DNS_RPC_ZONE_LIST_DOTNET ) +
sizeof( PDNS_RPC_ZONE_DOTNET ) * dwzonePtrCount );
pdataOut = pzonelistDotNet;
RtlCopyMemory(
( PBYTE ) pzonelistDotNet + DNS_DOTNET_VERSION_SIZE,
pzonelistW2K,
sizeof( DNS_RPC_ZONE_LIST_W2K ) +
sizeof( PDNS_RPC_ZONE_W2K ) * dwzonePtrCount );
pzonelistDotNet->dwRpcStructureVersion = DNS_RPC_ZONE_LIST_VER;
dwtypeOut = DNSSRV_TYPEID_ZONE_LIST;
//
// The zone array must also be converted. Count the new zones
// as they are successfully created so that if there's an error
// converting one zone we will still have a coherent structure.
//
pzonelistDotNet->dwZoneCount = 0;
for ( i = 0; status == ERROR_SUCCESS && i < dwzoneCount; ++i )
{
DWORD dwtype = DNSSRV_TYPEID_ZONE_W2K;
status = DnsRpc_ConvertToCurrent(
&dwtype,
&pzonelistDotNet->ZoneArray[ i ] );
if ( status != ERROR_SUCCESS )
{
ASSERT( status == ERROR_SUCCESS );
break;
}
ASSERT( dwtype == DNSSRV_TYPEID_ZONE );
++pzonelistDotNet->dwZoneCount;
}
break;
}
default:
break; // This struct requires no translation.
}
//
// Cleanup and return.
//
Done:
if ( pdwTypeId )
{
*pdwTypeId = dwtypeOut;
}
if ( ppData )
{
*ppData = pdataOut;
}
NoTranslation:
DNSDBG( STUB, (
"%s: status=%d\n type in=%d out=%d\n pdata in=%p out=%p\n", fn,
status,
dwtypeIn,
dwtypeOut,
pdataIn,
*ppData ));
return status;
} // DnsRpc_ConvertToCurrent
DNS_STATUS
DNS_API_FUNCTION
DnsRpc_ConvertToUnversioned(
IN PDWORD pdwTypeId, IN OUT
IN PVOID * ppData, IN OUT
IN BOOL * pfAllocatedRpcStruct OUT OPTIONAL
)
/*++
Routine Description:
Takes any DNS RPC structure as input and if necessary fabricates
the old-style unversioned revision of that structure from the members
of the input structure. This function is cousin to
DnsRpc_ConvertToCurrent.
If a new structure is allocated, the old one is freed and the pointer
value at ppData is replaced. Allocated points within the old struct
will be freed or copied to the new struct. Basically, the client
does not have to worry about freeing any part of the old struct. When
he's done with the new struct he has to free it and it's members, as
usual.
The main use of this function is to allow a new client to send
a new RPC structure (e.g. a ZONE_CREATE structure) to an old DNS
server transparently. This function will attempt to make intelligent
decisions about what to do if there are large functional differences
in the old and new structures.
Arguments:
pdwTypeId - type ID of object pointed to by ppData, value may be
changed to type ID of new object at ppData
ppData - pointer to object, pointer may be replaced by a pointer to
a newly allocated, completed different structure as required
pfAllocatedRpcStruct - if not NULL, value is set to TRUE if
a new structure is allocated by this function - the should request
this information if it needs to know if it should free the
replaced pData pointer using MIDL_user_free()
Return Value:
ERROR_SUCCESS or error code. If return code is not ERROR_SUCCESS, there
has been some kind of fatal error. Assume data invalid in this case.
--*/
{
DBG_FN( "DnsRpc_ConvertToUnversioned" )
DNS_STATUS status = ERROR_SUCCESS;
BOOL fallocatedRpcStruct = FALSE;
DWORD dwtypeIn = -1;
PVOID pdataIn = NULL;
DWORD dwtypeOut = -1;
PVOID pdataOut = NULL;
DWORD i;
if ( !pdwTypeId || !ppData )
{
ASSERT( pdwTypeId && ppData );
status = ERROR_INVALID_DATA;
goto NoTranslation;
}
//
// Shortcuts: do not translate NULL, any structure that is not
// versioned, or any structure that is already in unversioned
// format.
//
if ( *pdwTypeId <= DNSSRV_TYPEID_ZONE_LIST_W2K || *ppData == NULL )
{
goto NoTranslation;
}
dwtypeOut = dwtypeIn = *pdwTypeId;
pdataOut = pdataIn = *ppData;
fallocatedRpcStruct = TRUE;
//
// Giant switch statement of all types that can be downleveled.
//
switch ( dwtypeIn )
{
case DNSSRV_TYPEID_FORWARDERS:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_FORWARDERS_W2K );
RtlCopyMemory(
pdataOut,
( PBYTE ) pdataIn + DNS_DOTNET_VERSION_SIZE,
sizeof( DNS_RPC_FORWARDERS_W2K ) );
dwtypeOut = DNSSRV_TYPEID_FORWARDERS_W2K;
break;
case DNSSRV_TYPEID_ZONE_CREATE:
//
// .NET has several additional members.
//
{
PDNS_RPC_ZONE_CREATE_INFO_W2K pzoneOut;
PDNS_RPC_ZONE_CREATE_INFO pzoneIn = pdataIn;
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_CREATE_INFO_W2K );
pzoneOut = pdataOut;
pzoneOut->pszZoneName = pzoneIn->pszZoneName;
pzoneOut->dwZoneType = pzoneIn->dwZoneType;
pzoneOut->fAllowUpdate = pzoneIn->fAllowUpdate;
pzoneOut->fAging = pzoneIn->fAging;
pzoneOut->dwFlags = pzoneIn->dwFlags;
pzoneOut->pszDataFile = pzoneIn->pszDataFile;
pzoneOut->fDsIntegrated = pzoneIn->fDsIntegrated;
pzoneOut->fLoadExisting = pzoneIn->fLoadExisting;
pzoneOut->pszAdmin = pzoneIn->pszAdmin;
pzoneOut->aipMasters = pzoneIn->aipMasters;
pzoneOut->aipSecondaries = pzoneIn->aipSecondaries;
pzoneOut->fSecureSecondaries = pzoneIn->fSecureSecondaries;
pzoneOut->fNotifyLevel = pzoneIn->fNotifyLevel;
dwtypeOut = DNSSRV_TYPEID_ZONE_CREATE_W2K;
break;
}
case DNSSRV_TYPEID_ZONE_TYPE_RESET:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_TYPE_RESET_W2K );
RtlCopyMemory(
pdataOut,
( PBYTE ) pdataIn + DNS_DOTNET_VERSION_SIZE,
sizeof( DNS_RPC_ZONE_TYPE_RESET_W2K ) );
dwtypeOut = DNSSRV_TYPEID_ZONE_TYPE_RESET_W2K;
break;
case DNSSRV_TYPEID_ZONE_SECONDARIES:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_SECONDARIES_W2K );
RtlCopyMemory(
pdataOut,
( PBYTE ) pdataIn + DNS_DOTNET_VERSION_SIZE,
sizeof( DNS_RPC_ZONE_SECONDARIES_W2K ) );
dwtypeOut = DNSSRV_TYPEID_ZONE_SECONDARIES_W2K;
break;
case DNSSRV_TYPEID_ZONE_DATABASE:
//
// Structures are identical except for dwRpcStructureVersion.
//
ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_DATABASE_W2K );
RtlCopyMemory(
pdataOut,
( PBYTE ) pdataIn + DNS_DOTNET_VERSION_SIZE,
sizeof( DNS_RPC_ZONE_DATABASE_W2K ) );
dwtypeOut = DNSSRV_TYPEID_ZONE_DATABASE_W2K;
break;
default:
fallocatedRpcStruct = FALSE;
break; // Unknown - do nothing.
}
//
// Cleanup and return.
//
Done:
if ( pdwTypeId )
{
*pdwTypeId = dwtypeOut;
}
if ( ppData )
{
*ppData = pdataOut;
}
NoTranslation:
if ( pfAllocatedRpcStruct )
{
*pfAllocatedRpcStruct = fallocatedRpcStruct;
}
DNSDBG( STUB, (
"%s: status=%d\n type in=%d out=%d\n pdata in=%p out=%p\n", fn,
status,
dwtypeIn,
dwtypeOut,
pdataIn,
*ppData ));
return status;
} // DnsRpc_ConvertToUnversioned
//
// RPC functions
//
DNS_STATUS
DNS_API_FUNCTION
DnssrvOperationEx(
IN DWORD dwClientVersion,
IN DWORD dwSettingFlags,
IN LPCWSTR Server,
IN LPCSTR pszZone,
IN DWORD dwContext,
IN LPCSTR pszOperation,
IN DWORD dwTypeId,
IN PVOID pData
)
{
DNS_STATUS status;
DNSSRV_RPC_UNION rpcData;
BOOL fallocatedRpcStruct = FALSE;
DECLARE_DNS_RPC_RETRY_STATE( status );
if ( status != ERROR_SUCCESS )
{
return status;
}
rpcData.Null = pData;
IF_DNSDBG( STUB )
{
DNS_PRINT((
"Enter DnssrvOperationEx()\n"
"\tClient ver = 0x%X\n"
"\tServer = %S\n"
"\tZone = %s\n"
"\tContext = %p\n"
"\tOperation = %s\n"
"\tTypeid = %d\n",
dwClientVersion,
Server,
pszZone,
dwContext,
pszOperation,
dwTypeId ));
IF_DNSDBG( STUB2 )
{
DnsDbg_RpcUnion(
"pData for R_DnssrvOperationEx ",
dwTypeId,
rpcData.Null );
}
}
#if 0
// generate multizone context?
//
// DEVNOTE: get this working
if ( pszZone )
{
dwContext = DnssrvGenerateZoneOperationContext( pszZone, dwContext );
}
#endif
DECLARE_DNS_RPC_RETRY_LABEL()
RpcTryExcept
{
ASSERT_DNS_RPC_RETRY_STATE_VALID();
if ( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW )
{
status = R_DnssrvOperation2(
dwClientVersion,
dwSettingFlags,
Server,
pszZone,
dwContext,
pszOperation,
dwTypeId,
rpcData );
}
else
{
status = R_DnssrvOperation(
Server,
pszZone,
dwContext,
pszOperation,
dwTypeId,
rpcData );
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
IF_DNSDBG( STUB )
{
DNS_PRINT((
"Leave R_DnssrvOperation(): status %d (%p)\n",
status, status ));
}
}
RpcExcept (1)
{
status = RpcExceptionCode();
IF_DNSDBG( STUB )
{
DNS_PRINT((
"RpcExcept: code = %d (%p)\n",
status, status ));
}
//
// For downlevel server, attempt to construct old-style data.
//
DnsRpc_ConvertToUnversioned( &dwTypeId, &pData, &fallocatedRpcStruct );
rpcData.Null = pData;
ADVANCE_DNS_RPC_RETRY_STATE( status );
}
RpcEndExcept
TEST_DNS_RPC_RETRY();
printExtendedRpcErrorInfo( status );
if ( fallocatedRpcStruct )
{
MIDL_user_free( pData );
}
return status;
}
DNS_STATUS
DNS_API_FUNCTION
DnssrvQueryEx(
IN DWORD dwClientVersion,
IN DWORD dwSettingFlags,
IN LPCWSTR Server,
IN LPCSTR pszZone,
IN LPCSTR pszQuery,
OUT PDWORD pdwTypeId,
OUT PVOID * ppData
)
{
DNS_STATUS status;
DECLARE_DNS_RPC_RETRY_STATE( status );
if ( status != ERROR_SUCCESS )
{
return status;
}
IF_DNSDBG( STUB )
{
DNS_PRINT((
"Enter DnssrvQuery()\n"
"\tClient ver = 0x%X\n"
"\tServer = %S\n"
"\tZone = %s\n"
"\tQuery = %s\n",
dwClientVersion,
Server,
pszZone,
pszQuery ));
DNSDBG( STUB2, (
"\tpdwTypeId = %p\n"
"\tppData = %p\n"
"\t*pdwTypeId = %d\n"
"\t*ppData = %p\n",
pdwTypeId,
ppData,
*pdwTypeId,
*ppData ));
}
if ( !pszQuery || !ppData || !pdwTypeId )
{
DNS_ASSERT( FALSE );
return( ERROR_INVALID_PARAMETER );
}
//
// RPC sees ppData as actually a PTR to a UNION structure, and
// for pointer type returns, would like to copy the data back into the
// memory pointed at by the current value of the pointer.
//
// This is not what we want, we just want to capture a pointer to
// the returned data block. To do this init the pointer value to
// be NULL, so RPC will then allocate memory of all pointer types
// in the UNION.
//
*ppData = NULL;
DECLARE_DNS_RPC_RETRY_LABEL()
RpcTryExcept
{
ASSERT_DNS_RPC_RETRY_STATE_VALID();
if ( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW )
{
status = R_DnssrvQuery2(
dwClientVersion,
dwSettingFlags,
Server,
pszZone,
pszQuery,
pdwTypeId,
( DNSSRV_RPC_UNION * ) ppData );
}
else
{
status = R_DnssrvQuery(
Server,
pszZone,
pszQuery,
pdwTypeId,
( DNSSRV_RPC_UNION * ) ppData );
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
IF_DNSDBG( STUB )
{
DNS_PRINT((
"Leave R_DnssrvQuery(): status %d (%p)\n"
"\tTypeId = %d\n"
"\tDataPtr = %p\n",
status, status,
*pdwTypeId,
*ppData ));
if ( ppData )
{
DnsDbg_RpcUnion(
"After R_DnssrvQuery ...\n",
*pdwTypeId,
*ppData );
}
}
}
RpcExcept (1)
{
status = RpcExceptionCode();
IF_DNSDBG( STUB )
{
DNS_PRINT((
"RpcExcept: code = %d (%p)\n",
status, status ));
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
}
RpcEndExcept
TEST_DNS_RPC_RETRY();
//
// Upgrade old structure to new.
//
printExtendedRpcErrorInfo( status );
if ( status == ERROR_SUCCESS )
{
status = DnsRpc_ConvertToCurrent( pdwTypeId, ppData );
}
return status;
}
DNS_STATUS
DNS_API_FUNCTION
DnssrvComplexOperationEx(
IN DWORD dwClientVersion,
IN DWORD dwSettingFlags,
IN LPCWSTR Server,
IN LPCSTR pszZone,
IN LPCSTR pszOperation,
IN DWORD dwTypeIn,
IN PVOID pDataIn,
OUT PDWORD pdwTypeOut,
OUT PVOID * ppDataOut
)
{
DNS_STATUS status;
DNSSRV_RPC_UNION rpcData;
DECLARE_DNS_RPC_RETRY_STATE( status );
if ( status != ERROR_SUCCESS )
{
return status;
}
rpcData.Null = pDataIn;
IF_DNSDBG( STUB )
{
DNS_PRINT((
"Enter DnssrvComplexOperation()\n"
"\tClient ver = 0x%X\n"
"\tServer = %S\n"
"\tZone = %s\n"
"\tOperation = %s\n"
"\tTypeIn = %d\n",
dwClientVersion,
Server,
pszZone,
pszOperation,
dwTypeIn ));
IF_DNSDBG( STUB2 )
{
DnsDbg_RpcUnion(
"pData for R_DnssrvOperation ",
dwTypeIn,
rpcData.Null );
DNS_PRINT((
"\tpdwTypeOut = %p\n"
"\tppDataOut = %p\n"
"\t*pdwTypeOut = %d\n"
"\t*ppDataOut = %p\n",
pdwTypeOut,
ppDataOut,
*pdwTypeOut,
*ppDataOut ));
}
}
if ( !pszOperation || !ppDataOut || !pdwTypeOut )
{
DNS_ASSERT( FALSE );
return( ERROR_INVALID_PARAMETER );
}
//
// RPC sees ppDataOut as actually a PTR to a UNION structure, and
// for pointer type returns, would like to copy the data back into
// the memory pointed at by the current value of the pointer.
//
// This is not what we want, we just want to capture a pointer to
// the returned data block. To do this init the pointer value to
// be NULL, so RPC will then allocate memory of all pointer types
// in the UNION.
//
*ppDataOut = NULL;
DECLARE_DNS_RPC_RETRY_LABEL()
RpcTryExcept
{
ASSERT_DNS_RPC_RETRY_STATE_VALID();
if ( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW )
{
status = R_DnssrvComplexOperation2(
dwClientVersion,
dwSettingFlags,
Server,
pszZone,
pszOperation,
dwTypeIn,
rpcData,
pdwTypeOut,
( DNSSRV_RPC_UNION * ) ppDataOut );
}
else
{
status = R_DnssrvComplexOperation(
Server,
pszZone,
pszOperation,
dwTypeIn,
rpcData,
pdwTypeOut,
( DNSSRV_RPC_UNION * ) ppDataOut );
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
IF_DNSDBG( STUB )
{
DNS_PRINT((
"Leave R_DnssrvComplexOperation(): status %d (%p)\n"
"\tTypeId = %d\n"
"\tDataPtr = %p\n",
status, status,
*pdwTypeOut,
*ppDataOut ));
if ( ppDataOut )
{
DnsDbg_RpcUnion(
"After R_DnssrvQuery ...\n",
*pdwTypeOut,
*ppDataOut );
}
}
}
RpcExcept (1)
{
status = RpcExceptionCode();
IF_DNSDBG( STUB )
{
DNS_PRINT((
"RpcExcept: code = %d (%p)\n",
status, status ));
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
}
RpcEndExcept
TEST_DNS_RPC_RETRY();
printExtendedRpcErrorInfo( status );
//
// Upgrade old structure to new.
//
if ( status == ERROR_SUCCESS )
{
status = DnsRpc_ConvertToCurrent( pdwTypeOut, ppDataOut );
}
return status;
}
DNS_STATUS
DNS_API_FUNCTION
DnssrvEnumRecordsEx(
IN DWORD dwClientVersion,
IN DWORD dwSettingFlags,
IN LPCWSTR Server,
IN LPCSTR pszZoneName,
IN LPCSTR pszNodeName,
IN LPCSTR pszStartChild,
IN WORD wRecordType,
IN DWORD dwSelectFlag,
IN LPCSTR pszFilterStart,
IN LPCSTR pszFilterStop,
IN OUT PDWORD pdwBufferLength,
OUT PBYTE * ppBuffer
)
/*++
Routine Description:
Stub for EnumRecords API.
Note, this matches DnssrvEnumRecords() API exactly.
The "Stub" suffix is attached to distinguish from the actual
DnssrvEnumRecords() (remote.c) which handles NT4 server compatibility.
When that is no longer desired, that routine may be eliminated and
this the "Stub" suffix removed from this routine.
Arguments:
Return Value:
ERROR_SUCCESS on successful enumeration.
ERROR_MORE_DATA when buffer full and more data remains.
ErrorCode on failure.
--*/
{
DNS_STATUS status;
DECLARE_DNS_RPC_RETRY_STATE( status );
if ( status != ERROR_SUCCESS )
{
return status;
}
DNSDBG( STUB, (
"Enter DnssrvEnumRecords()\n"
"\tClient ver = 0x%X\n"
"\tServer = %S\n"
"\tpszZoneName = %s\n"
"\tpszNodeName = %s\n"
"\tpszStartChild = %s\n"
"\twRecordType = %d\n"
"\tdwSelectFlag = %p\n"
"\tpszFilterStart = %s\n"
"\tpszFilterStop = %s\n"
"\tpdwBufferLength = %p\n"
"\tppBuffer = %p\n",
dwClientVersion,
Server,
pszZoneName,
pszNodeName,
pszStartChild,
wRecordType,
dwSelectFlag,
pszFilterStart,
pszFilterStop,
pdwBufferLength,
ppBuffer ));
DECLARE_DNS_RPC_RETRY_LABEL()
RpcTryExcept
{
// clear ptr for safety, we don't want to free any bogus memory
*ppBuffer = NULL;
ASSERT_DNS_RPC_RETRY_STATE_VALID();
if ( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW )
{
status = R_DnssrvEnumRecords2(
dwClientVersion,
dwSettingFlags,
Server,
pszZoneName,
pszNodeName,
pszStartChild,
wRecordType,
dwSelectFlag,
pszFilterStart,
pszFilterStop,
pdwBufferLength,
ppBuffer );
}
else
{
status = R_DnssrvEnumRecords(
Server,
pszZoneName,
pszNodeName,
pszStartChild,
wRecordType,
dwSelectFlag,
pszFilterStart,
pszFilterStop,
pdwBufferLength,
ppBuffer );
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
IF_DNSDBG( STUB )
{
DNS_PRINT((
"R_DnssrvEnumRecords: try = %d status = %d / %p\n",
DNS_RPC_RETRY_STATE(),
status,
status ));
if ( status == ERROR_SUCCESS || status == ERROR_MORE_DATA )
{
DnsDbg_RpcRecordsInBuffer(
"Returned records: ",
*pdwBufferLength,
*ppBuffer );
}
}
}
RpcExcept (1)
{
status = RpcExceptionCode();
IF_DNSDBG( STUB )
{
DNS_PRINT((
"RpcExcept: code = %d / %p\n",
status,
status ));
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
}
RpcEndExcept
TEST_DNS_RPC_RETRY();
printExtendedRpcErrorInfo( status );
return status;
}
DNS_STATUS
DNS_API_FUNCTION
DnssrvUpdateRecordEx(
IN DWORD dwClientVersion,
IN DWORD dwSettingFlags,
IN LPCWSTR Server,
IN LPCSTR pszZoneName,
IN LPCSTR pszNodeName,
IN PDNS_RPC_RECORD pAddRecord,
IN PDNS_RPC_RECORD pDeleteRecord
)
/*++
Routine Description:
Stub for UpdateRecords API.
Arguments:
Return Value:
ERROR_SUCCESS on successful enumeration.
ErrorCode on failure.
--*/
{
DNS_STATUS status;
DECLARE_DNS_RPC_RETRY_STATE( status );
if ( status != ERROR_SUCCESS )
{
return status;
}
DNSDBG( STUB, (
"Enter R_DnssrvUpdateRecord()\n"
"\tClient ver = 0x%X\n"
"\tServer = %S\n"
"\tpszZoneName = %s\n"
"\tpszNodeName = %s\n"
"\tpAddRecord = %p\n"
"\tpDeleteRecord = %p\n",
dwClientVersion,
Server,
pszZoneName,
pszNodeName,
pAddRecord,
pDeleteRecord ));
DECLARE_DNS_RPC_RETRY_LABEL()
RpcTryExcept
{
ASSERT_DNS_RPC_RETRY_STATE_VALID();
if ( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW )
{
status = R_DnssrvUpdateRecord2(
dwClientVersion,
dwSettingFlags,
Server,
pszZoneName,
pszNodeName,
pAddRecord,
pDeleteRecord );
}
else
{
status = R_DnssrvUpdateRecord(
Server,
pszZoneName,
pszNodeName,
pAddRecord,
pDeleteRecord );
}
ADVANCE_DNS_RPC_RETRY_STATE( status );
DNSDBG( STUB, (
"R_DnssrvUpdateRecord: status = %d / %p\n",
status, status ));
}
RpcExcept (1)
{
status = RpcExceptionCode();
DNSDBG( STUB, (
"RpcExcept: code = %d / %p\n",
status, status ));
ADVANCE_DNS_RPC_RETRY_STATE( status );
}
RpcEndExcept
TEST_DNS_RPC_RETRY();
printExtendedRpcErrorInfo( status );
return status;
}
//
// End stub.c
//