/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Copyright (c) 1993-2000 Microsoft Corporation Module Name : auxilary.c Abstract : This file contains auxilary routines used for initialization of the RPC and stub messages and the offline batching of common code sequences needed by the stubs. Author : David Kays dkays September 1993. Revision History : ---------------------------------------------------------------------*/ #define _OLE32_ #include "ndrp.h" #include "ndrole.h" #include "ndrtypes.h" #include "limits.h" #include "interp.h" #include "mulsyntx.h" #include "pipendr.h" #include "asyncndr.h" #include "auxilary.h" /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Static data for NS library operations ---------------------------------------------------------------------*/ int NsDllLoaded = 0; /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ OLE routines for interface pointer marshalling ---------------------------------------------------------------------*/ STDAPI NdrpCoCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv); STDAPI NdrpCoReleaseMarshalData( IStream *pStm); STDAPI NdrpDcomChannelSetHResult( PRPC_MESSAGE pmsg, ULONG * pulReserved, HRESULT appsHR ); STDAPI NdrCoGetPSClsid( REFIID iid, LPCLSID lpclsid); HINSTANCE hOle32 = 0; RPC_GET_CLASS_OBJECT_ROUTINE NdrCoGetClassObject; RPC_GET_CLASS_OBJECT_ROUTINE * pfnCoGetClassObject = &NdrCoGetClassObject; RPC_GET_MARSHAL_SIZE_MAX_ROUTINE NdrCoGetMarshalSizeMax; RPC_GET_MARSHAL_SIZE_MAX_ROUTINE * pfnCoGetMarshalSizeMax = &NdrCoGetMarshalSizeMax; RPC_MARSHAL_INTERFACE_ROUTINE NdrCoMarshalInterface; RPC_MARSHAL_INTERFACE_ROUTINE * pfnCoMarshalInterface = &NdrCoMarshalInterface; RPC_UNMARSHAL_INTERFACE_ROUTINE NdrCoUnmarshalInterface; RPC_UNMARSHAL_INTERFACE_ROUTINE * pfnCoUnmarshalInterface = &NdrCoUnmarshalInterface; RPC_STRING_FROM_IID OleStringFromIID; RPC_STRING_FROM_IID * pfnStringFromIID = &OleStringFromIID; RPC_GET_PS_CLSID NdrCoGetPSClsid; RPC_GET_PS_CLSID * pfnCoGetPSClsid = &NdrCoGetPSClsid; RPC_CO_CREATE_INSTANCE NdrpCoCreateInstance; RPC_CO_CREATE_INSTANCE * pfnCoCreateInstance = &NdrpCoCreateInstance; RPC_CLIENT_ALLOC NdrCoTaskMemAlloc; RPC_CLIENT_ALLOC * pfnCoTaskMemAlloc = &NdrCoTaskMemAlloc; RPC_CLIENT_FREE NdrCoTaskMemFree; RPC_CLIENT_FREE * pfnCoTaskMemFree = &NdrCoTaskMemFree; RPC_CO_RELEASEMARSHALDATA NdrpCoReleaseMarshalData; RPC_CO_RELEASEMARSHALDATA * pfnCoReleaseMarshalData = &NdrpCoReleaseMarshalData; RPC_DCOMCHANNELSETHRESULT NdrpDcomChannelSetHResult; RPC_DCOMCHANNELSETHRESULT * pfnDcomChannelSetHResult = &NdrpDcomChannelSetHResult; RPC_NS_GET_BUFFER_ROUTINE pRpcNsGetBuffer; RPC_NS_SEND_RECEIVE_ROUTINE pRpcNsSendReceive; RPC_NS_NEGOTIATETRANSFERSYNTAX_ROUTINE pRpcNsNegotiateTransferSyntax; HRESULT NdrLoadOleRoutines() { void * pTempRoutine; //Load ole32.dll if(hOle32 == 0) { #ifdef DOSWIN32RPC hOle32 = LoadLibraryA("OLE32"); #else hOle32 = LoadLibraryW(L"OLE32"); #endif // DOSWIN32C if(hOle32 == 0) return HRESULT_FROM_WIN32(GetLastError()); } pTempRoutine = GetProcAddress(hOle32, "CoGetClassObject"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoGetClassObject = (RPC_GET_CLASS_OBJECT_ROUTINE*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoGetMarshalSizeMax"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoGetMarshalSizeMax = (RPC_GET_MARSHAL_SIZE_MAX_ROUTINE*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoMarshalInterface"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoMarshalInterface = (RPC_MARSHAL_INTERFACE_ROUTINE*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoUnmarshalInterface"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoUnmarshalInterface = (RPC_UNMARSHAL_INTERFACE_ROUTINE*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "StringFromIID"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnStringFromIID = (RPC_STRING_FROM_IID*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoGetPSClsid"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoGetPSClsid = (RPC_GET_PS_CLSID*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoTaskMemAlloc"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoTaskMemAlloc = (RPC_CLIENT_ALLOC*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoTaskMemFree"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoTaskMemFree = (RPC_CLIENT_FREE*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoCreateInstance"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoCreateInstance = (RPC_CO_CREATE_INSTANCE*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "CoReleaseMarshalData"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnCoReleaseMarshalData = (RPC_CO_RELEASEMARSHALDATA*) pTempRoutine; pTempRoutine = GetProcAddress(hOle32, "DcomChannelSetHResult"); if(pTempRoutine == 0) return HRESULT_FROM_WIN32(GetLastError()); else pfnDcomChannelSetHResult = (RPC_DCOMCHANNELSETHRESULT*) pTempRoutine; return( (HRESULT)0 ); } HRESULT STDAPICALLTYPE NdrCoGetClassObject( REFCLSID rclsid, DWORD dwClsContext, void *pvReserved, REFIID riid, void **ppv) /*++ Routine Description: Loads a class factory. This function forwards the call to ole32.dll. Arguments: rclsid - Supplies the CLSID of the class to be loaded. dwClsContext - Supplies the context in which to load the code. pvReserved - Must be NULL. riid - Supplies the IID of the desired interface. ppv - Returns a pointer to the class factory. Return Value: S_OK --*/ { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnCoGetClassObject)(rclsid, dwClsContext, pvReserved, riid, ppv); } HRESULT STDAPICALLTYPE NdrCoGetMarshalSizeMax( ULONG * pulSize, REFIID riid, LPUNKNOWN pUnk, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags) /*++ Routine Description: Calculates the maximum size of a marshalled interface pointer. This function forwards the call to ole32.dll. Arguments: pulSize - Returns an upper bound for the size of a marshalled interface pointer. riid - Supplies the IID of the interface to be marshalled. pUnk - Supplies a pointer to the object to be marshalled. dwDestContext - Supplies the destination of the marshalled interface pointer. pvDestContext mshlflags - Flags. See the MSHFLAGS enumeration. Return Value: S_OK --*/ { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnCoGetMarshalSizeMax)(pulSize, riid, pUnk, dwDestContext, pvDestContext, mshlflags); } RPC_STATUS RPC_ENTRY NdrGetDcomProtocolVersion( PMIDL_STUB_MESSAGE pStubMsg, RPC_VERSION * pVersion ) /* This is a helper routine for OLEAUT guys. It returns the actually negotiated protocol version for the connection, i.e. a "common denominator" - lower of the two. */ { HRESULT Hr = E_FAIL; if ( pStubMsg->pRpcChannelBuffer ) { IRpcChannelBuffer2 * pBuffer2 = 0; Hr = ((IRpcChannelBuffer*)pStubMsg->pRpcChannelBuffer)-> QueryInterface( IID_IRpcChannelBuffer2, (void**) & pBuffer2 ); if ( Hr == S_OK ) { Hr = pBuffer2->GetProtocolVersion( (DWORD *) pVersion ); pBuffer2->Release( ); } } return Hr; } unsigned long FixWireRepForDComVerGTE54( PMIDL_STUB_MESSAGE pStubMsg ) /* Compares the current DCOM protocol version with the desired version ( 5.4 ) Specific to interface pointer array and embedded conf struct wire rep fix. */ { if ( pStubMsg->pRpcChannelBuffer ) { RPC_VERSION currRpcVersion = { 0, 0 }; if ( SUCCEEDED ( NdrGetDcomProtocolVersion( pStubMsg, &currRpcVersion ) ) ) { if ( currRpcVersion.MajorVersion > 5 ) { return TRUE; } else { return currRpcVersion.MinorVersion >= 4; } } } return TRUE; } HRESULT STDAPICALLTYPE NdrCoMarshalInterface( LPSTREAM pStm, REFIID riid, LPUNKNOWN pUnk, DWORD dwDestContext, LPVOID pvDestContext, DWORD mshlflags) /*++ Routine Description: Marshals an interface pointer. This function forwards the call to ole32.dll. Arguments: pStm - Supplies the target stream. riid - Supplies the IID of the interface to be marshalled. pUnk - Supplies a pointer to the object to be marshalled. dwDestContext - Specifies the destination context pvDestContext mshlflags - Flags. See the MSHFLAGS enumeration. Return Value: S_OK --*/ { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnCoMarshalInterface)(pStm, riid, pUnk, dwDestContext, pvDestContext, mshlflags); } HRESULT STDAPICALLTYPE NdrCoUnmarshalInterface( LPSTREAM pStm, REFIID riid, void ** ppv) /*++ Routine Description: Unmarshals an interface pointer from a stream. This function forwards the call to ole32.dll. Arguments: pStm - Supplies the stream containing the marshalled interface pointer. riid - Supplies the IID of the interface pointer to be unmarshalled. ppv - Returns the unmarshalled interface pointer. Return Value: S_OK --*/ { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnCoUnmarshalInterface)(pStm, riid, ppv); } STDAPI NdrpCoCreateInstance( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv) { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnCoCreateInstance) (rclsid, pUnkOuter, dwClsContext, riid, ppv ); } STDAPI NdrpCoReleaseMarshalData( IStream *pStm) { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnCoReleaseMarshalData) (pStm ); } STDAPI NdrpDcomChannelSetHResult( PRPC_MESSAGE pmsg, ULONG * pulReserved, HRESULT appsHR ) { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnDcomChannelSetHResult)( pmsg, pulReserved, appsHR ); } HRESULT STDAPICALLTYPE OleStringFromIID( REFIID rclsid, LPOLESTR FAR* lplpsz) /*++ Routine Description: Converts an IID into a string. This function forwards the call to ole32.dll. Arguments: rclsid - Supplies the clsid to convert to string form. lplpsz - Returns the string form of the clsid (with "{}" around it). Return Value: S_OK --*/ { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnStringFromIID)(rclsid, lplpsz); } STDAPI NdrCoGetPSClsid( REFIID iid, LPCLSID lpclsid) /*++ Routine Description: Converts an IID into a string. This function forwards the call to ole32.dll. Arguments: rclsid - Supplies the clsid to convert to string form. lplpsz - Returns the string form of the clsid (with "{}" around it). Return Value: S_OK --*/ { HRESULT hr; if ( FAILED(hr = NdrLoadOleRoutines()) ) return hr; return (*pfnCoGetPSClsid)(iid, lpclsid); } void * STDAPICALLTYPE NdrCoTaskMemAlloc( size_t cb) /*++ Routine Description: Allocate memory using OLE task memory allocator. This function forwards the call to ole32.dll. Arguments: cb - Specifies the amount of memory to be allocated. Return Value: This function returns a pointer to the allocated memory. If an error occurs, this function returns zero. --*/ { if ( FAILED(NdrLoadOleRoutines()) ) return 0; return (*pfnCoTaskMemAlloc)(cb); } void STDAPICALLTYPE NdrCoTaskMemFree( void * pMemory) /*++ Routine Description: Free memory using OLE task memory allocator. This function forwards the call to ole32.dll. Arguments: pMemory - Supplies a pointer to the memory to be freed. Return Value: None. --*/ { if ( FAILED(NdrLoadOleRoutines()) ) return; (*pfnCoTaskMemFree)(pMemory); } void * RPC_ENTRY NdrOleAllocate(size_t size) /*++ Routine Description: Allocate memory via OLE task allocator. Arguments: size - Specifies the amount of memory to be allocated. Return Value: This function returns a pointer to the allocated memory. If an error occurs, this function raises an exception. --*/ { void *pMemory; pMemory = (*pfnCoTaskMemAlloc)(size); if(pMemory == 0) RpcRaiseException(E_OUTOFMEMORY); return pMemory; } void RPC_ENTRY NdrOleFree(void *pMemory) /*++ Routine Description: Free memory using OLE task allocator. Arguments: None. Return Value: None. --*/ { (*pfnCoTaskMemFree)(pMemory); } HRESULT STDAPICALLTYPE NdrStringFromIID( REFIID rclsid, char * lpsz) /*++ Routine Description: Converts an IID into a string. This function forwards the call to ole32.dll. Arguments: rclsid - Supplies the clsid to convert to string form. lplpsz - Returns the string form of the clsid (with "{}" around it). Return Value: S_OK --*/ { HRESULT hr; wchar_t * olestr; hr = (*pfnStringFromIID)(rclsid, &olestr); if(SUCCEEDED(hr)) { WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)olestr, -1, (LPSTR)lpsz, 50, NULL, NULL); NdrOleFree(olestr); } return hr; } void RPC_ENTRY NdrClientInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, PMIDL_STUB_DESC pStubDescriptor, unsigned int ProcNum ) /*++ Routine Description : This routine is called by client side stubs to initialize the RPC message and stub message, and to get the RPC buffer. Arguments : pRpcMsg - pointer to RPC message structure pStubMsg - pointer to stub message structure pStubDescriptor - pointer to stub descriptor structure HandleType - type of binding handle ProcNum - remote procedure number --*/ { NdrClientInitialize( pRpcMsg, pStubMsg, pStubDescriptor, ProcNum ); if ( pStubDescriptor->pMallocFreeStruct ) { MALLOC_FREE_STRUCT *pMFS = pStubDescriptor->pMallocFreeStruct; NdrpSetRpcSsDefaults(pMFS->pfnAllocate, pMFS->pfnFree); } // This exception should be raised after initializing StubMsg. if ( pStubDescriptor->Version > NDR_VERSION ) { NDR_ASSERT( 0, "ClientInitialize : Bad version number" ); RpcRaiseException( RPC_X_WRONG_STUB_VERSION ); } // // This is where we initialize fields behind the NT3.5 - NT5.0 field set. // #ifdef _CS_CHAR_ if ( NDR_VERSION_6_0 <= pStubDescriptor->Version ) { pStubMsg->pCSInfo = 0; } #endif // _CS_CHAR_ } void RPC_ENTRY NdrClientInitialize( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, PMIDL_STUB_DESC pStubDescriptor, unsigned int ProcNum ) /*++ Routine Description : This routine is called by client side stubs to initialize the RPC message and stub message, and to get the RPC buffer. Arguments : pRpcMsg - pointer to RPC message structure pStubMsg - pointer to stub message structure pStubDescriptor - pointer to stub descriptor structure ProcNum - remote procedure number Notes: This routine has to be backward compatible with the old binaries built from -Os stubs. In particular, it cannot touch StubMsg fields outside of the NT3.5 - NT5.0 field set, i.e. set of fields present since NT3.5 release. --*/ { // // Initialize RPC message fields. // // The leftmost bit of the procnum field is supposed to be set to 1 inr // order for the runtime to know if it is talking to the older stubs or // not. // pRpcMsg->RpcInterfaceInformation = pStubDescriptor->RpcInterfaceInformation; //#if !defined(__RPC_WIN64__) pRpcMsg->ProcNum = ProcNum | RPC_FLAGS_VALID_BIT; //#endif pRpcMsg->RpcFlags = 0; pRpcMsg->Handle = 0; // // Initialize the Stub messsage fields. // pStubMsg->RpcMsg = pRpcMsg; pStubMsg->StubDesc = pStubDescriptor; pStubMsg->pfnAllocate = pStubDescriptor->pfnAllocate; pStubMsg->pfnFree = pStubDescriptor->pfnFree; pStubMsg->fInDontFree = 0; pStubMsg->fDontCallFreeInst = 0; pStubMsg->fInOnlyParam = 0; pStubMsg->fHasReturn = 0; pStubMsg->fHasExtensions = 0; pStubMsg->fHasNewCorrDesc = 0; pStubMsg->fUnused = 0; pStubMsg->IsClient = TRUE; pStubMsg->BufferLength = 0; pStubMsg->BufferStart = 0; pStubMsg->BufferEnd = 0; pStubMsg->uFlags = 0; pStubMsg->fBufferValid = FALSE; pStubMsg->ReuseBuffer = FALSE; pStubMsg->StackTop = 0; pStubMsg->IgnoreEmbeddedPointers = FALSE; pStubMsg->PointerBufferMark = 0; pStubMsg->pAllocAllNodesContext = 0; pStubMsg->pPointerQueueState = 0; pStubMsg->FullPtrRefId = 0; pStubMsg->PointerLength = 0; pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE; pStubMsg->pvDestContext = 0; pStubMsg->pRpcChannelBuffer = 0; pStubMsg->pArrayInfo = 0; pStubMsg->dwStubPhase = 0; NdrSetupLowStackMark( pStubMsg ); pStubMsg->pAsyncMsg = 0; pStubMsg->pCorrInfo = 0; pStubMsg->pCorrMemory = 0; pStubMsg->pMemoryList = 0; } void MakeSureWeHaveNonPipeArgs( PMIDL_STUB_MESSAGE pStubMsg, unsigned long BufferSize ) /* Routine description: This routine is called for pipe calls at the server. After the runtime dispatched to the stub with the first packet, it makes sure that we have a portion of the buffer big enough to keep all the non-pipe args. Arguments: BufferSize - a pipe call: addtional number of bytes over what we have. Note: The buffer location may change from before to after the call. */ { RPC_STATUS Status; PRPC_MESSAGE pRpcMsg = pStubMsg->RpcMsg; if ( !(pRpcMsg->RpcFlags & RPC_BUFFER_COMPLETE ) ) { // May be the args fit into the first packet. if ( BufferSize <= pRpcMsg->BufferLength ) return; // Set the partial flag to get the non-pipe args. // For a partial call with the "extra", the meaning of the size // arg is the addition required above what we have already. pRpcMsg->RpcFlags |= (RPC_BUFFER_PARTIAL | RPC_BUFFER_EXTRA); // We will receive at least BufferSize. // (buffer location may change) BufferSize -= pRpcMsg->BufferLength; Status = I_RpcReceive( pRpcMsg, (unsigned int) BufferSize ); if ( Status != RPC_S_OK ) { // Note, that for this particular error case, i.e. non-pipe // data receive failing, we don't want to restore the // original dispatch buffer into the rpc message. // In case of an error the buffer coming back here would be 0. // RpcRaiseException( Status ); } NDR_ASSERT( 0 == BufferSize || NULL != pRpcMsg->Buffer, "Rpc runtime returned an invalid buffer."); // In case this is a new buffer pStubMsg->Buffer = (uchar*)pRpcMsg->Buffer; pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->BufferStart + pRpcMsg->BufferLength; } } unsigned char * RPC_ENTRY NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, PMIDL_STUB_DESC pStubDescriptor ) /*++ Routine Description : This routine is called by the server stubs before unmarshalling. It initializes the stub message fields. Aruguments : pStubMsg - pointer to the stub message structure pStubDescriptor - pointer to the stub descriptor structure Note. NdrServerInitializeNew is almost identical to NdrServerInitializePartial. NdrServerInitializeNew is generated for non-pipes and is backward comp. NdrServerInitializePartial is generated for routines with pipes args. --*/ { NdrServerInitialize( pRpcMsg, pStubMsg, pStubDescriptor ); if ( pStubDescriptor->pMallocFreeStruct ) { MALLOC_FREE_STRUCT *pMFS = pStubDescriptor->pMallocFreeStruct; NdrpSetRpcSsDefaults(pMFS->pfnAllocate, pMFS->pfnFree); } // This exception should be raised after initializing StubMsg. if ( pStubDescriptor->Version > NDR_VERSION ) { NDR_ASSERT( 0, "ServerInitializeNew : bad version number" ); RpcRaiseException( RPC_X_WRONG_STUB_VERSION ); } // // This is where we initialize fields behind the NT3.5 - NT5.0 field set. // #ifdef _CS_CHAR_ if ( NDR_VERSION_6_0 <= pStubDescriptor->Version ) { pStubMsg->pCSInfo = 0; } #endif // _CS_CHAR_ if ( !(pRpcMsg->RpcFlags & RPC_BUFFER_COMPLETE ) ) { // A non-pipe call with an incomplete buffer. // This can happen only for non-pipe calls in an interface that // has some pipe calls. RPC_STATUS Status; pRpcMsg->RpcFlags = RPC_BUFFER_EXTRA; // The size argument is ignored, we will get everything. Status = I_RpcReceive( pRpcMsg, 0 ); if ( Status != RPC_S_OK ) { // This is the same behavior (and comment) as in MakeSure.. // routine above for non-pipe data case in a pipe call. // For this particular error case, i.e. a call to Receive to get // all (non-pipe) data failing, we don't want to restore the // original dispatch buffer into the rpc message. // In case of an error the buffer coming back here would be 0. // RpcRaiseException( Status ); } NDR_ASSERT( 0 == pRpcMsg->BufferLength || NULL != pRpcMsg->Buffer, "Rpc runtime returned an invalid buffer."); // In case this is a new buffer pStubMsg->Buffer = (uchar*)pRpcMsg->Buffer; pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->BufferStart + pRpcMsg->BufferLength; } return 0; } unsigned char * RPC_ENTRY NdrServerInitialize( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, PMIDL_STUB_DESC pStubDescriptor ) /*++ Routine Description : This routine is called by the server stubs before unmarshalling. It initializes the stub message fields. Aruguments : pStubMsg - pointer to the stub message structure pStubDescriptor - pointer to the stub descriptor structure Note : This is a core server-side initializer, called by everybody. This routine has to be backward compatible with the old binaries built from -Os stubs. In particular, it cannot touch StubMsg fields outside of the NT3.5 - NT5.0 field set, i.e. set of fields present since NT3.5 release. --*/ { pStubMsg->IsClient = FALSE; pStubMsg->pAllocAllNodesContext = 0; pStubMsg->pPointerQueueState = 0; pStubMsg->IgnoreEmbeddedPointers = FALSE; pStubMsg->PointerBufferMark = 0; pStubMsg->BufferLength = 0; pStubMsg->StackTop = 0; pStubMsg->FullPtrXlatTables = 0; pStubMsg->FullPtrRefId = 0; pStubMsg->PointerLength = 0; pStubMsg->fDontCallFreeInst = 0; pStubMsg->fInDontFree = 0; pStubMsg->fInOnlyParam = 0; pStubMsg->fHasReturn = 0; pStubMsg->fHasExtensions = 0; pStubMsg->fHasNewCorrDesc = 0; pStubMsg->fUnused = 0; pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE; pStubMsg->pvDestContext = 0; pStubMsg->pRpcChannelBuffer = 0; pStubMsg->pArrayInfo = 0; pStubMsg->RpcMsg = pRpcMsg; pStubMsg->Buffer = (uchar*)pRpcMsg->Buffer; // // Set BufferStart and BufferEnd before unmarshalling. // NdrPointerFree uses these values to detect pointers into the // rpc message buffer. // pStubMsg->BufferStart = (uchar*)pRpcMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->BufferStart + pRpcMsg->BufferLength; pStubMsg->uFlags = 0; pStubMsg->pfnAllocate = pStubDescriptor->pfnAllocate; pStubMsg->pfnFree = pStubDescriptor->pfnFree; pStubMsg->StubDesc = pStubDescriptor; pStubMsg->ReuseBuffer = FALSE; pStubMsg->dwStubPhase = 0; NdrSetupLowStackMark( pStubMsg ); pStubMsg->pAsyncMsg = 0; pStubMsg->pCorrInfo = 0; pStubMsg->pCorrMemory = 0; pStubMsg->pMemoryList = 0; NdrRpcSetNDRSlot( pStubMsg ); return(0); } void RPC_ENTRY NdrServerInitializePartial( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, PMIDL_STUB_DESC pStubDescriptor, unsigned long RequestedBufferSize ) /*++ Routine Description : This routine is called by the server stubs for pipes. It is almost identical to NdrServerInitializeNew, except that it calls NdrpServerInitialize. Aruguments : pStubMsg - pointer to the stub message structure pStubDescriptor - pointer to the stub descriptor structure pBuffer - pointer to the beginning of the RPC message buffer --*/ { NdrServerInitialize( pRpcMsg, pStubMsg, pStubDescriptor ); if ( pStubDescriptor->pMallocFreeStruct ) { MALLOC_FREE_STRUCT *pMFS = pStubDescriptor->pMallocFreeStruct; NdrpSetRpcSsDefaults(pMFS->pfnAllocate, pMFS->pfnFree); } // This exception should be raised after initializing StubMsg. if ( pStubDescriptor->Version > NDR_VERSION ) { NDR_ASSERT( 0, "ServerInitializePartial : bad version number" ); RpcRaiseException( RPC_X_WRONG_STUB_VERSION ); } // // This is where we initialize fields behind the NT3.5 - NT5.0 field set. // #ifdef _CS_CHAR_ if ( NDR_VERSION_6_0 <= pStubDescriptor->Version ) { pStubMsg->pCSInfo = 0; } #endif _CS_CHAR_ // Last but not least... MakeSureWeHaveNonPipeArgs( pStubMsg, RequestedBufferSize ); } unsigned char * RPC_ENTRY NdrGetBuffer( PMIDL_STUB_MESSAGE pStubMsg, unsigned long BufferLength, RPC_BINDING_HANDLE Handle ) /*++ Routine Description : Performs an RpcGetBuffer. Arguments : pStubMsg - Pointer to stub message structure. BufferLength - Length of requested rpc message buffer. Handle - Bound handle. --*/ { RPC_STATUS Status; if ( pStubMsg->IsClient ) pStubMsg->RpcMsg->Handle = pStubMsg->SavedHandle = Handle; pStubMsg->RpcMsg->BufferLength = BufferLength; Status = I_RpcGetBuffer( pStubMsg->RpcMsg ); if ( Status ) { // For raw rpc, if async, don't call abort later. if ( pStubMsg->pAsyncMsg ) pStubMsg->pAsyncMsg->Flags.RuntimeCleanedUp = 1; RpcRaiseException( Status ); } NDR_ASSERT( 0 == BufferLength || NULL != pStubMsg->RpcMsg->Buffer, "Rpc runtime returned an invalid buffer."); NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7), "marshaling buffer misaligned" ); pStubMsg->Buffer = (uchar *) pStubMsg->RpcMsg->Buffer; pStubMsg->fBufferValid = TRUE; return pStubMsg->Buffer; } void EnsureNSLoaded() /*++ Routine Description : Guarantee that the RpcNs4 DLL is loaded. Throw exception if unable to load it. Will load the RpcNs4 DLL if not already loaded Arguments : --*/ { HINSTANCE DllHandle; LPSTR EntryName; if ( NsDllLoaded ) return; #ifdef DOSWIN32RPC DllHandle = LoadLibraryA( "RPCNS4" ); #else DllHandle = LoadLibraryW( L"RPCNS4" ); #endif // DOSWIN32RPC if ( DllHandle == 0 ) { RpcRaiseException (RPC_S_INVALID_BINDING); } EntryName = "I_RpcNsGetBuffer"; pRpcNsGetBuffer = (RPC_NS_GET_BUFFER_ROUTINE) GetProcAddress( DllHandle, EntryName); if ( pRpcNsGetBuffer == 0 ) { RpcRaiseException (RPC_S_INVALID_BINDING); } EntryName = "I_RpcNsSendReceive"; pRpcNsSendReceive = (RPC_NS_SEND_RECEIVE_ROUTINE) GetProcAddress( DllHandle, EntryName); if ( pRpcNsSendReceive == 0 ) { RpcRaiseException (RPC_S_INVALID_BINDING); } EntryName = "I_RpcNsNegotiateTransferSyntax"; pRpcNsNegotiateTransferSyntax = ( RPC_NS_NEGOTIATETRANSFERSYNTAX_ROUTINE ) GetProcAddress( DllHandle, EntryName ); if ( pRpcNsNegotiateTransferSyntax == 0 ) { RpcRaiseException (RPC_S_INVALID_BINDING); } NsDllLoaded = 1; } unsigned char * RPC_ENTRY NdrNsGetBuffer( PMIDL_STUB_MESSAGE pStubMsg, unsigned long BufferLength, RPC_BINDING_HANDLE Handle ) /*++ Routine Description : Performs an RpcNsGetBuffer. Will load the RpcNs4 DLL if not already loaded Arguments : pStubMsg - Pointer to stub message structure. BufferLength - Length of requested rpc message buffer. Handle - Bound handle --*/ { RPC_STATUS Status; if( pStubMsg->IsClient == TRUE ) pStubMsg->RpcMsg->Handle = pStubMsg->SavedHandle = Handle; EnsureNSLoaded(); pStubMsg->RpcMsg->BufferLength = BufferLength; Status = (*pRpcNsGetBuffer)( pStubMsg->RpcMsg ); if ( Status ) RpcRaiseException( Status ); NDR_ASSERT( ! ((ULONG_PTR)pStubMsg->RpcMsg->Buffer & 0x7), "marshaling buffer misaligned" ); pStubMsg->Buffer = (uchar *) pStubMsg->RpcMsg->Buffer; pStubMsg->fBufferValid = TRUE; return pStubMsg->Buffer; } unsigned char * RPC_ENTRY NdrSendReceive( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferEnd ) /*++ Routine Description : Performs an RpcSendRecieve. This routine is executed for the non-pipe calls only. It returns a whole marshaling buffer. Arguments : pStubMsg - Pointer to stub message structure. pBufferEnd - End of the rpc message buffer being sent. Return : The new message buffer pointer returned from the runtime after the SendReceive call to the server. --*/ { RPC_STATUS Status; PRPC_MESSAGE pRpcMsg; pRpcMsg = pStubMsg->RpcMsg; if ( pRpcMsg->BufferLength < (uint)(pBufferEnd - (uchar *)pRpcMsg->Buffer)) { NDR_ASSERT( 0, "NdrSendReceive : buffer overflow" ); RpcRaiseException( RPC_S_INTERNAL_ERROR ); } pRpcMsg->BufferLength = (ulong)(pBufferEnd - (uchar *)pRpcMsg->Buffer); pStubMsg->fBufferValid = FALSE; Status = I_RpcSendReceive( pRpcMsg ); if ( Status ) RpcRaiseException(Status); NDR_ASSERT( 0 == pRpcMsg->BufferLength || NULL != pRpcMsg->Buffer, "Rpc runtime returned an invalid buffer."); NDR_ASSERT( ! ((ULONG_PTR)pRpcMsg->Buffer & 0x7), "marshaling buffer misaligned" ); pStubMsg->Buffer = (uchar*)pRpcMsg->Buffer; pStubMsg->BufferStart = pStubMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->Buffer + pRpcMsg->BufferLength; pStubMsg->fBufferValid = TRUE; return 0; } unsigned char * RPC_ENTRY NdrNsSendReceive( PMIDL_STUB_MESSAGE pStubMsg, uchar * pBufferEnd, RPC_BINDING_HANDLE * pAutoHandle ) /*++ Routine Description : Performs an RpcNsSendRecieve for a procedure which uses an auto handle. Will load the RpcNs4 DLL if not already loaded Arguments : pStubMsg - Pointer to stub message structure. pBufferEnd - End of the rpc message buffer being sent. pAutoHandle - Pointer to the auto handle used in the call. Return : The new message buffer pointer returned from the runtime after the SendReceive call to the server. --*/ { RPC_STATUS Status; PRPC_MESSAGE pRpcMsg; EnsureNSLoaded(); pRpcMsg = pStubMsg->RpcMsg; if ( pRpcMsg->BufferLength < (uint)(pBufferEnd - (uchar *)pRpcMsg->Buffer) ) { NDR_ASSERT( 0, "NdrNsSendReceive : buffer overflow" ); RpcRaiseException( RPC_S_INTERNAL_ERROR ); } pRpcMsg->BufferLength = (ulong)(pBufferEnd - (uchar *)pRpcMsg->Buffer); pStubMsg->fBufferValid = FALSE; Status = (*pRpcNsSendReceive)( pRpcMsg, pAutoHandle ); if ( Status ) RpcRaiseException(Status); pStubMsg->SavedHandle = *pAutoHandle; pStubMsg->Buffer = (uchar*)pRpcMsg->Buffer; pStubMsg->BufferStart = pStubMsg->Buffer; pStubMsg->BufferEnd = pStubMsg->Buffer + pRpcMsg->BufferLength; pStubMsg->fBufferValid = TRUE; return pStubMsg->Buffer; } void RPC_ENTRY NdrFreeBuffer( PMIDL_STUB_MESSAGE pStubMsg ) /*++ Routine Description : Performs an RpcFreeBuffer. Arguments : pStubMsg - pointer to stub message structure Return : None. --*/ { RPC_STATUS Status; if ( ! pStubMsg->fBufferValid ) return; if( ! pStubMsg->RpcMsg->Handle ) return; Status = I_RpcFreeBuffer( pStubMsg->RpcMsg ); pStubMsg->fBufferValid = FALSE; if ( Status ) RpcRaiseException(Status); } void * RPC_ENTRY NdrAllocate( PMIDL_STUB_MESSAGE pStubMsg, size_t Len ) /*++ Routine Description : Private allocator. Handles allocate all nodes cases. Arguments : pStubMsg - Pointer to stub message structure. Len - Number of bytes to allocate. Return : Valid memory pointer. --*/ { void * pMemory; if ( pStubMsg->pAllocAllNodesContext ) { // // We must guarantee 4 byte alignment on NT and MAC. // #if defined(__RPC_WIN64__) ALIGN(pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory,7); #else ALIGN(pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory,3); #endif // Get the pointer. pMemory = pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory; // Increment the block pointer. pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory += Len; // // Check for memory allocs past the end of our allocated buffer. // if ( pStubMsg->pAllocAllNodesContext->AllocAllNodesMemoryEnd < pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory ) { NDR_ASSERT( pStubMsg->pAllocAllNodesContext->AllocAllNodesMemory <= pStubMsg->pAllocAllNodesContext->AllocAllNodesMemoryEnd, "Not enough alloc all nodes memory!" ); RpcRaiseException( RPC_S_INTERNAL_ERROR ); } return pMemory; } else { size_t NodeOffset, FullSize; PNDR_MEMORY_LIST_TAIL_NODE pMemoryList; // Add linked list node to tail of allocation. Ensure that the tail // is at a 8 byte alignment so that the same code will work in 64bits. NodeOffset = Len; LENGTH_ALIGN(NodeOffset, 7); FullSize = NodeOffset + sizeof(NDR_MEMORY_LIST_TAIL_NODE); if ( ! (pMemory = (*pStubMsg->pfnAllocate)( FullSize )) ) RpcRaiseException( RPC_S_OUT_OF_MEMORY ); pMemoryList = (PNDR_MEMORY_LIST_TAIL_NODE)((char *)pMemory + NodeOffset); pMemoryList->Signature = NDR_MEMORY_LIST_SIGNATURE; pMemoryList->pMemoryHead = pMemory; pMemoryList->pNextNode = (PNDR_MEMORY_LIST_TAIL_NODE)pStubMsg->pMemoryList; pStubMsg->pMemoryList = pMemoryList; return pMemory; } } void NdrpFreeMemoryList( MIDL_STUB_MESSAGE * pStubMsg) /*++ Routine Description : Freeing the list of memory allocated by NdrAllocate. Arguments : pStubMsg - Pointer to stub message structure. Return : None. --*/ { RpcTryExcept { while(pStubMsg->pMemoryList) { PNDR_MEMORY_LIST_TAIL_NODE pMemoryList = (PNDR_MEMORY_LIST_TAIL_NODE)pStubMsg->pMemoryList; if (pMemoryList->Signature != NDR_MEMORY_LIST_SIGNATURE) { NDR_ASSERT( 0 , "bad rpc allocated memory signature" ); return; } pStubMsg->pMemoryList = pMemoryList->pNextNode; (*pStubMsg->pfnFree)(pMemoryList->pMemoryHead); } } RpcExcept(1) { // Something is wrong and perhaps memory has been corrupted. If this happens, // just ignore the exception and stop freeing memory. This will duplicate the // behavior of NDR without the linked list. } RpcEndExcept } unsigned char * RPC_ENTRY NdrServerInitializeUnmarshall ( PMIDL_STUB_MESSAGE pStubMsg, PMIDL_STUB_DESC pStubDescriptor, PRPC_MESSAGE pRpcMsg ) /*++ Routine Description : Old NT Beta2 (build 683) server stub initialization routine. Used for backward compatability only. Aruguments : pStubMsg - Pointer to the stub message structure. pStubDescriptor - Pointer to the stub descriptor structure. pBuffer - Pointer to the beginning of the RPC message buffer. --*/ { return NdrServerInitialize( pRpcMsg, pStubMsg, pStubDescriptor ); } void RPC_ENTRY NdrServerInitializeMarshall ( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg ) /*++ Routine Description : Old NT Beta2 (build 683) server stub initialization routine. Used for backward compatability only. Arguments : pRpcMsg - Pointer to the RPC message structure. pStubMsg - Pointer to the stub message structure. --*/ { } // // Functions to simulate a alloca across a function call. // Note that this code is optimized for simplicity and speed. It does // not attempt to search a list on each allocation to reuse partially full // blocks as much as it could. This gives max speed, but hurts space // utilization when allocations of significantly different sizes are requested. // // This code can easily be optimized more in the future. #if defined(NDR_PROFILE_ALLOCA) VOID NdrpAllocaWriteLog( CHAR *pChar, DWORD Size ) { HANDLE hMutex = NULL; HANDLE hLogFile = INVALID_HANDLE_VALUE; BOOL bHasMutex = FALSE; RpcTryFinally { // Open and acquire the log mutex hMutex = CreateMutex( NULL, FALSE, "NDR_ALLOCA_LOG_MUTEX"); if ( !hMutex) return; DWORD dwWaitResult = WaitForSingleObject( hMutex, INFINITE ); if ( WAIT_FAILED == dwWaitResult ) return; bHasMutex = TRUE; CHAR LogFile[MAX_PATH]; UINT DirResult = GetSystemDirectoryA( LogFile, sizeof(LogFile) ); if ( !DirResult) return; strcat( LogFile, "\\ndralloca.log" ); hLogFile = CreateFileA( LogFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, NULL ); SetFilePointer( hLogFile, 0, NULL, FILE_END ); DWORD dwBytesWritten; WriteFile( hLogFile, pChar, Size, &dwBytesWritten, NULL ); } RpcFinally { if ( bHasMutex ) ReleaseMutex( hMutex ); if ( NULL != hMutex) CloseHandle( hMutex ); if ( INVALID_HANDLE_VALUE != hLogFile ) CloseHandle( hLogFile ); } RpcEndFinally } VOID NdrpAllocaDumpStatistics( PNDR_ALLOCA_CONTEXT pAllocaContext ) { // Produce a record suitable for entry into Excel. CHAR DataBuffer[4048]; CHAR AppName[MAX_PATH]; memset(AppName, 0, sizeof(AppName ) ); GetModuleFileNameA( NULL, AppName, sizeof(AppName ) ); sprintf( DataBuffer, "EXE,%s,PID,0x%X,TID,0x%x,CS,%d,AB,%d,AA,%d,MB,%d,MA,%d\r\n", AppName, GetCurrentProcessId(), GetCurrentThreadId(), (long)NDR_ALLOCA_PREALLOCED_BLOCK_SIZE, pAllocaContext->AllocaBytes, pAllocaContext->AllocaAllocations, pAllocaContext->MemoryBytes, pAllocaContext->MemoryAllocations ); NdrpAllocaWriteLog( DataBuffer, strlen( DataBuffer ) ); } #endif VOID NdrpAllocaInit( PNDR_ALLOCA_CONTEXT pAllocaContext ) /*++ Routine Description : Initiaizes the alloca context. Arguments : pAllocaContext - Pointer to the Alloca context.. Return : None. --*/ { pAllocaContext->pBlockPointer = pAllocaContext->PreAllocatedBlock; pAllocaContext->BytesRemaining = NDR_ALLOCA_PREALLOCED_BLOCK_SIZE; #if defined(NDR_PROFILE_ALLOCA) pAllocaContext->AllocaBytes = 0; pAllocaContext->AllocaAllocations = 0; pAllocaContext->MemoryBytes = 0; pAllocaContext->MemoryAllocations = 0; #endif InitializeListHead( &pAllocaContext->MemoryList ); } VOID NdrpAllocaDestroy( PNDR_ALLOCA_CONTEXT pAllocaContext ) /*++ Routine Description : Deinitializes this Alloca context and frees all memory from the allocation calls that were associated with this context. Arguments : pAllocaContext - Pointer to the Alloca context. Return : None. --*/ { #if defined(NDR_PROFILE_ALLOCA) NdrpAllocaDumpStatistics( pAllocaContext ); #endif PLIST_ENTRY pMemoryList = pAllocaContext->MemoryList.Flink; while( pMemoryList != &pAllocaContext->MemoryList ) { PLIST_ENTRY pMemoryListNext = pMemoryList->Flink; I_RpcFree( pMemoryList ); pMemoryList = pMemoryListNext; } InitializeListHead( &pAllocaContext->MemoryList ); } PVOID NdrpAlloca( PNDR_ALLOCA_CONTEXT pAllocaContext, UINT Size ) /*++ Routine Description : Allocates memory from the allocation context. If no memory is available in the cache, more memory is added. If more memory can not be added, a RPC_S_NO_MEMORY exception is raised. Arguments : pAllocaContext - Pointer to the Alloca context. Size - Size of the memory to allocate. Return : Newly allocated memory. --*/ { PVOID pReturnedBlock; LENGTH_ALIGN( Size, 15 ); #if defined(NDR_PROFILE_ALLOCA) pAllocaContext->AllocaAllocations++; pAllocaContext->AllocaBytes += Size; #endif // Check if the current block has enough memory to handle the request. if (Size > pAllocaContext->BytesRemaining) { // Allocate a new block ULONG NewBlockSize = max( Size + sizeof(LIST_ENTRY), NDR_ALLOCA_MIN_BLOCK_SIZE ); #if defined(NDR_PROFILE_ALLOCA) pAllocaContext->MemoryAllocations++; pAllocaContext->MemoryBytes += NewBlockSize; #endif PBYTE pNewBlock = (PBYTE)I_RpcAllocate( NewBlockSize ); if ( !pNewBlock ) { RpcRaiseException( RPC_S_OUT_OF_MEMORY ); return NULL; // keep the compiler happy } InsertHeadList( &pAllocaContext->MemoryList, (PLIST_ENTRY) pNewBlock); pAllocaContext->pBlockPointer = pNewBlock + sizeof(LIST_ENTRY); pAllocaContext->BytesRemaining = NewBlockSize - sizeof(LIST_ENTRY); } // alloc memory from an existing block. pReturnedBlock = pAllocaContext->pBlockPointer; pAllocaContext->pBlockPointer += Size; pAllocaContext->BytesRemaining -= Size; return pReturnedBlock; } PVOID NdrpPrivateAllocate( PNDR_ALLOCA_CONTEXT pAllocaContext, UINT Size ) /*++ Routine Description : Allocates memory using I_RpcAllocate and adds the memory to the memory list block. If no memory is available, and RPC_S_OUT_OF_MEMORY exception is thrown. Arguments : pAllocaContext - Pointer to the Alloca context. Size - Size of the memory to allocate. Return : Newly allocated memory. --*/ { UINT AllocSize = sizeof(LIST_ENTRY) + Size; PBYTE pNewBlock = (PBYTE)I_RpcAllocate( AllocSize ); if ( !pNewBlock ) { RpcRaiseException( RPC_S_OUT_OF_MEMORY ); return NULL; // keep the compiler happy } InsertHeadList( &pAllocaContext->MemoryList, (PLIST_ENTRY) pNewBlock); return ((uchar *)pNewBlock) + sizeof(PLIST_ENTRY); } void NdrpPrivateFree( PNDR_ALLOCA_CONTEXT pAllocaContext, void *pMemory ) /*++ Routine Description : Frees memory allocated with NdrpPrivateAllocate Arguments : pAllocaContext - Pointer to the Alloca context. pMemory - Memory allocated with NdrpPrivateAllocate. Return : None. --*/ { PLIST_ENTRY pListEntry; if (NULL == pMemory) return; pListEntry = (PLIST_ENTRY)( ((uchar *)pMemory) - sizeof(LIST_ENTRY) ); RemoveEntryList( pListEntry ); I_RpcFree( pListEntry ); } void NdrpInitUserMarshalCB( MIDL_STUB_MESSAGE * pStubMsg, PFORMAT_STRING pFormat, USER_MARSHAL_CB_TYPE CBType, USER_MARSHAL_CB * pUserMarshalCB ) /*++ Routine Description : Initialize a user marshall callback structure. Arguments : pStubMsg - Supplies the stub message for the call. pFormat - Supplies the format string for the type(FC_USER_MARSHAL). CBType - Supplies the callback type. pUserMarshalCB - Pointer to the callback to be initialized. Return : None. --*/ { pUserMarshalCB->Flags = USER_CALL_CTXT_MASK( pStubMsg->dwDestContext ); if ( USER_MARSHAL_CB_UNMARSHALL == CBType ) { pUserMarshalCB->Flags |= (((pStubMsg->RpcMsg->DataRepresentation & (ulong)0x0000FFFF)) << 16 ); } if ( pStubMsg->pAsyncMsg ) pUserMarshalCB->Flags |= USER_CALL_IS_ASYNC; if ( pStubMsg->fHasNewCorrDesc ) pUserMarshalCB->Flags |= USER_CALL_NEW_CORRELATION_DESC; pUserMarshalCB->pStubMsg = pStubMsg; pUserMarshalCB->pReserve = (pFormat[1] & USER_MARSHAL_IID) ? pFormat + 10 : 0; pUserMarshalCB->Signature = USER_MARSHAL_CB_SIGNATURE; pUserMarshalCB->CBType = CBType; pUserMarshalCB->pFormat = pFormat; pUserMarshalCB->pTypeFormat = pFormat + 8; pUserMarshalCB->pTypeFormat = pUserMarshalCB->pTypeFormat + *(short *)pUserMarshalCB->pTypeFormat; } RPC_STATUS RPC_ENTRY NdrGetUserMarshalInfo ( IN unsigned long * pFlags, IN unsigned long InformationLevel, OUT NDR_USER_MARSHAL_INFO * pMarshalInfo ) /*++ Routine Description : The NdrGetUserMarshalInfo function is called by a application provided wire_marshal or user_marshal helper function to receive extra information in addition to the pFlags parameter. Arguments : pFlags - Supplies the pFlags pointer that rpc passed to the helper function. InformationLevel - Supplies the desired level of detail to be received. The amount of information increases as the level increases. pMarshalInfo - Points to the buffer that is to receive the extra information. Return : On sucesss - RPC_S_OK. --*/ { MIDL_STUB_MESSAGE *pStubMsg; USER_MARSHAL_CB * pCBInfo = (USER_MARSHAL_CB *)pFlags; if ( InformationLevel != 1) { return RPC_S_INVALID_ARG; } RpcTryExcept { if ( USER_MARSHAL_CB_SIGNATURE != pCBInfo->Signature ) { return RPC_S_INVALID_ARG; } MIDL_memset( pMarshalInfo, 0, sizeof(NDR_USER_MARSHAL_INFO) ); } RpcExcept(1) { return RPC_S_INVALID_ARG; } RpcEndExcept pMarshalInfo->InformationLevel = InformationLevel; pStubMsg = pCBInfo->pStubMsg; // The buffer pointer and the buffer length only // make sense if the callback is for marshalling // and unmarshalling. if ( USER_MARSHAL_CB_MARSHALL == pCBInfo->CBType || USER_MARSHAL_CB_UNMARSHALL == pCBInfo->CBType ) { char *CurrentBuffer = (char *)pStubMsg->Buffer; char *BufferStart = (char *)pStubMsg->RpcMsg->Buffer; unsigned long BufferUsed = (unsigned long)(ULONG_PTR)(CurrentBuffer - BufferStart); unsigned long BufferLength = pStubMsg->RpcMsg->BufferLength - BufferUsed; if ( CurrentBuffer < BufferStart || CurrentBuffer > (BufferStart + pStubMsg->RpcMsg->BufferLength ) ) { return RPC_X_INVALID_BUFFER; } pMarshalInfo->Level1.Buffer = pStubMsg->Buffer; pMarshalInfo->Level1.BufferSize = BufferLength; } pMarshalInfo->Level1.pfnAllocate = pStubMsg->pfnAllocate; pMarshalInfo->Level1.pfnFree = pStubMsg->pfnFree; pMarshalInfo->Level1.pRpcChannelBuffer = pStubMsg->pRpcChannelBuffer; pMarshalInfo->Level1.Reserved[0] = (ULONG_PTR)pCBInfo->pFormat; pMarshalInfo->Level1.Reserved[1] = (ULONG_PTR)pCBInfo->pTypeFormat; return RPC_S_OK; } void RPC_ENTRY RpcUserFree( HANDLE AsyncHandle, void * pBuffer ) { PMIDL_STUB_MESSAGE pStubMsg; RPC_STATUS Status; PRPC_ASYNC_STATE pHandle = ( PRPC_ASYNC_STATE) AsyncHandle; // User passes in NULL in sync case. if ( NULL == pHandle ) { pStubMsg = (PMIDL_STUB_MESSAGE )I_RpcGetNDRSlot(); Status = S_OK; } else { Status = NdrValidateBothAndLockAsyncHandle( pHandle); if ( Status == RPC_S_OK ) { PNDR_ASYNC_MESSAGE pAsyncMsg = (PNDR_ASYNC_MESSAGE) pHandle->StubInfo; pStubMsg = &pAsyncMsg->StubMsg; } } // REVIEW: default behavior is not to raise exception? if ( Status != RPC_S_OK ) { NDR_ASSERT( 0, "invalid rpc handle" ); return ; } // validate the stubmsg. NDR_ASSERT( pStubMsg, "invalid stub message" ); // We'll call into user's free routine to free the buffer if it's not // part of dispatch buffer. // We don't care about allocate_on_stack: it can only happen on top level // out ref pointer or ref pointer to pointer case, and freeing that is // very much shooting self on the foot. if ( (pBuffer < pStubMsg->BufferStart) || (pBuffer > pStubMsg->BufferEnd)) { pStubMsg->pfnFree( pBuffer ); } else return; } BOOL IsWriteAV ( IN struct _EXCEPTION_POINTERS *ExceptionPointers ) { EXCEPTION_RECORD *ExceptionRecord; ExceptionRecord = ExceptionPointers->ExceptionRecord; if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) && (ExceptionRecord->ExceptionInformation[0])) { return TRUE; } else return FALSE; } int RPC_ENTRY NdrServerUnmarshallExceptionFlag( IN struct _EXCEPTION_POINTERS *ExceptionPointers ) { RPC_STATUS ExceptCode = ExceptionPointers->ExceptionRecord->ExceptionCode; if ( ( ExceptCode != STATUS_POSSIBLE_DEADLOCK ) && ( ExceptCode != STATUS_INSTRUCTION_MISALIGNMENT ) && ( ExceptCode != STATUS_DATATYPE_MISALIGNMENT ) && ( ExceptCode != STATUS_PRIVILEGED_INSTRUCTION ) && ( ExceptCode != STATUS_ILLEGAL_INSTRUCTION ) && ( ExceptCode != STATUS_BREAKPOINT ) && ( ExceptCode != STATUS_STACK_OVERFLOW ) && !IsWriteAV(ExceptionPointers) ) return EXCEPTION_EXECUTE_HANDLER; else return EXCEPTION_CONTINUE_SEARCH; } // check for overflow when calculating the total size. #if defined(_X86_) ULONG MultiplyWithOverflowCheck( ULONG_PTR Count, ULONG_PTR ELemSize ) { register UINT32 IsOverFlowed = 0; NDR_ASSERT( Count < 0x80000000, "invalid count" ); NDR_ASSERT( ELemSize < 0x80000000 , "invalid element size" ); ULONG res = Count * ELemSize; __asm { jno skip; mov IsOverFlowed, 1; skip: } if ( IsOverFlowed || res > 0x7fffffff ) RpcRaiseException( RPC_X_INVALID_BOUND ); return res; } #else // we only have ia64 & amd64 here. ULONG MultiplyWithOverflowCheck( ULONG_PTR Count, ULONG_PTR ElemSize ) { NDR_ASSERT( Count < 0x80000000, "invalid count" ); NDR_ASSERT( ElemSize < 0x80000000 , "invalid element size" ); UINT64 res = (UINT64)Count * ElemSize; if ( res > 0x7fffffff ) RpcRaiseException( RPC_X_INVALID_BOUND ); return (ULONG) res ; } #endif