/*++ 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 #define DBG_FN( funcName ) static const char * fn = (funcName); #else #define DBG_FN( funcName ) #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_STATE() INT DNS_RPC_RETRY_STATE() = 0 #define DECLARE_DNS_RPC_RETRY_LABEL() DnsRpcRetryLabel: #define ADVANCE_DNS_RPC_RETRY_STATE( dwStatus ) \ if ( DNS_RPC_RETRY_STATE() == DNS_RPC_TRY_NEW && \ ( dwStatus == ERROR_SUCCESS || \ dwStatus < RPC_S_INVALID_STRING_BINDING || \ dwStatus > RPC_X_BAD_STUB_DATA ) ) \ DNS_RPC_RETRY_STATE() = DNS_RPC_TRY_DONE; \ else \ ++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##_WHISTLER ) >= \ 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 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_WHISTLER_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: // // Structures are identical except for dwRpcStuctureVersion // and some usage in Whistler 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_SERVER_INFO_WHISTLER ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_SERVER_INFO_W2K ) ); ( ( PDNS_RPC_SERVER_INFO_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = DNS_RPC_SERVER_INFO_VER; dwtypeOut = DNSSRV_TYPEID_SERVER_INFO; break; case DNSSRV_TYPEID_FORWARDERS_W2K: // // Structures are identical except for dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_FORWARDERS_WHISTLER ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_FORWARDERS_W2K ) ); ( ( PDNS_RPC_FORWARDERS_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = DNS_RPC_FORWARDERS_VER; dwtypeOut = DNSSRV_TYPEID_FORWARDERS; break; case DNSSRV_TYPEID_ZONE_W2K: // // Structures are identical except for dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_WHISTLER ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_ZONE_W2K ) ); ( ( PDNS_RPC_ZONE_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = DNS_RPC_ZONE_VER; dwtypeOut = DNSSRV_TYPEID_ZONE; break; case DNSSRV_TYPEID_ZONE_INFO_W2K: // // Whistler 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_WHISTLER ); RtlZeroMemory( pdataOut, sizeof( DNS_RPC_ZONE_INFO_WHISTLER ) ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_ZONE_INFO_W2K ) ); ( ( PDNS_RPC_ZONE_INFO_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = DNS_RPC_ZONE_VER; dwtypeOut = DNSSRV_TYPEID_ZONE_INFO; break; case DNSSRV_TYPEID_ZONE_SECONDARIES_W2K: // // Structures are identical except for dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_SECONDARIES_WHISTLER ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_ZONE_SECONDARIES_W2K ) ); ( ( PDNS_RPC_ZONE_SECONDARIES_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = DNS_RPC_ZONE_SECONDARIES_VER; dwtypeOut = DNSSRV_TYPEID_ZONE_SECONDARIES; break; case DNSSRV_TYPEID_ZONE_DATABASE_W2K: // // Structures are identical except for dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_DATABASE_WHISTLER ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_ZONE_DATABASE_W2K ) ); ( ( PDNS_RPC_ZONE_DATABASE_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = DNS_RPC_ZONE_DATABASE_VER; dwtypeOut = DNSSRV_TYPEID_ZONE_DATABASE; break; case DNSSRV_TYPEID_ZONE_TYPE_RESET_W2K: // // Structures are identical except for dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_TYPE_RESET_WHISTLER ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_ZONE_TYPE_RESET_W2K ) ); ( ( PDNS_RPC_ZONE_TYPE_RESET_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = DNS_RPC_ZONE_TYPE_RESET_VER; dwtypeOut = DNSSRV_TYPEID_ZONE_TYPE_RESET; break; case DNSSRV_TYPEID_ZONE_CREATE_W2K: // // Structures are identical except for dwRpcStuctureVersion // and some usage in Whistler 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_WHISTLER ); RtlCopyMemory( ( PBYTE ) pdataOut + DNS_WHISTLER_VERSION_SIZE, pdataIn, sizeof( DNS_RPC_ZONE_CREATE_INFO_W2K ) ); ( ( PDNS_RPC_ZONE_CREATE_INFO_WHISTLER ) pdataOut )-> dwRpcStuctureVersion = 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_WHISTLER pzonelistWhistler; PDNS_RPC_ZONE_LIST_W2K pzonelistW2K; // // Structures are identical except for dwRpcStuctureVersion. // 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( pzonelistWhistler, sizeof( DNS_RPC_ZONE_LIST_WHISTLER ) + sizeof( PDNS_RPC_ZONE_WHISTLER ) * dwzonePtrCount ); pdataOut = pzonelistWhistler; RtlCopyMemory( ( PBYTE ) pzonelistWhistler + DNS_WHISTLER_VERSION_SIZE, pzonelistW2K, sizeof( DNS_RPC_ZONE_LIST_W2K ) + sizeof( PDNS_RPC_ZONE_W2K ) * dwzonePtrCount ); pzonelistWhistler->dwRpcStuctureVersion = 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. // pzonelistWhistler->dwZoneCount = 0; for ( i = 0; status == ERROR_SUCCESS && i < dwzoneCount; ++i ) { DWORD dwtype = DNSSRV_TYPEID_ZONE_W2K; status = DnsRpc_ConvertToCurrent( &dwtype, &pzonelistWhistler->ZoneArray[ i ] ); if ( status != ERROR_SUCCESS ) { ASSERT( status == ERROR_SUCCESS ); break; } ASSERT( dwtype == DNSSRV_TYPEID_ZONE ); ++pzonelistWhistler->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 dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_FORWARDERS_W2K ); RtlCopyMemory( pdataOut, ( PBYTE ) pdataIn + DNS_WHISTLER_VERSION_SIZE, sizeof( DNS_RPC_FORWARDERS_W2K ) ); dwtypeOut = DNSSRV_TYPEID_FORWARDERS_W2K; break; case DNSSRV_TYPEID_ZONE_CREATE: // // Whistler 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 dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_TYPE_RESET_W2K ); RtlCopyMemory( pdataOut, ( PBYTE ) pdataIn + DNS_WHISTLER_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 dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_SECONDARIES_W2K ); RtlCopyMemory( pdataOut, ( PBYTE ) pdataIn + DNS_WHISTLER_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 dwRpcStuctureVersion. // ALLOCATE_RPC_STRUCT( pdataOut, DNS_RPC_ZONE_DATABASE_W2K ); RtlCopyMemory( pdataOut, ( PBYTE ) pdataIn + DNS_WHISTLER_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(); 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(); 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(); 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. // 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(); 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(); // // 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(); 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(); 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(); 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(); return( status ); } // // End stub.c //