/* * NDR Serialization Services * * Copyright (c) 2007 Robert Shearman for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include "windef.h" #include "winbase.h" #include "winerror.h" #include "rpc.h" #include "midles.h" #include "ndrtypes.h" #include "ndr_misc.h" #include "ndr_stubless.h" #include "wine/debug.h" #include "wine/rpcfc.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); static inline void init_MIDL_ES_MESSAGE(MIDL_ES_MESSAGE *pEsMsg) { memset(pEsMsg, 0, sizeof(*pEsMsg)); /* even if we are unmarshalling, as we don't want pointers to be pointed * to buffer memory */ pEsMsg->StubMsg.IsClient = TRUE; pEsMsg->MesVersion = 1; } /*********************************************************************** * MesEncodeIncrementalHandleCreate [RPCRT4.@] */ RPC_STATUS WINAPI MesEncodeIncrementalHandleCreate( void *UserState, MIDL_ES_ALLOC AllocFn, MIDL_ES_WRITE WriteFn, handle_t *pHandle) { MIDL_ES_MESSAGE *pEsMsg; TRACE("(%p, %p, %p, %p)\n", UserState, AllocFn, WriteFn, pHandle); pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg)); if (!pEsMsg) return RPC_S_OUT_OF_MEMORY; init_MIDL_ES_MESSAGE(pEsMsg); pEsMsg->Operation = MES_ENCODE; pEsMsg->UserState = UserState; pEsMsg->HandleStyle = MES_INCREMENTAL_HANDLE; pEsMsg->Alloc = AllocFn; pEsMsg->Write = WriteFn; *pHandle = (handle_t)pEsMsg; return RPC_S_OK; } /*********************************************************************** * MesDecodeIncrementalHandleCreate [RPCRT4.@] */ RPC_STATUS WINAPI MesDecodeIncrementalHandleCreate( void *UserState, MIDL_ES_READ ReadFn, handle_t *pHandle) { MIDL_ES_MESSAGE *pEsMsg; TRACE("(%p, %p, %p)\n", UserState, ReadFn, pHandle); pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg)); if (!pEsMsg) return RPC_S_OUT_OF_MEMORY; init_MIDL_ES_MESSAGE(pEsMsg); pEsMsg->Operation = MES_DECODE; pEsMsg->UserState = UserState; pEsMsg->HandleStyle = MES_INCREMENTAL_HANDLE; pEsMsg->Read = ReadFn; *pHandle = (handle_t)pEsMsg; return RPC_S_OK; } /*********************************************************************** * MesIncrementalHandleReset [RPCRT4.@] */ RPC_STATUS WINAPI MesIncrementalHandleReset( handle_t Handle, void *UserState, MIDL_ES_ALLOC AllocFn, MIDL_ES_WRITE WriteFn, MIDL_ES_READ ReadFn, MIDL_ES_CODE Operation) { MIDL_ES_MESSAGE *pEsMsg = Handle; TRACE("(%p, %p, %p, %p, %p, %d)\n", Handle, UserState, AllocFn, WriteFn, ReadFn, Operation); init_MIDL_ES_MESSAGE(pEsMsg); pEsMsg->Operation = Operation; pEsMsg->UserState = UserState; pEsMsg->HandleStyle = MES_INCREMENTAL_HANDLE; pEsMsg->Alloc = AllocFn; pEsMsg->Write = WriteFn; pEsMsg->Read = ReadFn; return RPC_S_OK; } /*********************************************************************** * MesBufferHandleReset [RPCRT4.@] */ RPC_STATUS WINAPI MesBufferHandleReset(handle_t Handle, ULONG HandleStyle, MIDL_ES_CODE Operation, char **Buffer, ULONG BufferSize, ULONG *EncodedSize) { MIDL_ES_MESSAGE *pEsMsg = (MIDL_ES_MESSAGE *)Handle; TRACE("(%p, %u, %d, %p, %u, %p)\n", Handle, HandleStyle, Operation, Buffer, BufferSize, EncodedSize); if (!Handle || !Buffer || !EncodedSize) return RPC_S_INVALID_ARG; if (Operation != MES_ENCODE && Operation != MES_DECODE && Operation != MES_ENCODE_NDR64) return RPC_S_INVALID_ARG; if (HandleStyle != MES_FIXED_BUFFER_HANDLE && HandleStyle != MES_DYNAMIC_BUFFER_HANDLE) return RPC_S_INVALID_ARG; init_MIDL_ES_MESSAGE(pEsMsg); pEsMsg->Operation = Operation; pEsMsg->HandleStyle = HandleStyle; if (HandleStyle == MES_FIXED_BUFFER_HANDLE) pEsMsg->Buffer = (unsigned char*)*Buffer; else pEsMsg->pDynBuffer = (unsigned char**)Buffer; pEsMsg->BufferSize = BufferSize; pEsMsg->pEncodedSize = EncodedSize; return RPC_S_OK; } /*********************************************************************** * MesHandleFree [RPCRT4.@] */ RPC_STATUS WINAPI MesHandleFree(handle_t Handle) { TRACE("(%p)\n", Handle); HeapFree(GetProcessHeap(), 0, Handle); return RPC_S_OK; } static RPC_STATUS validate_mes_buffer_pointer(const char *Buffer) { if (!Buffer) return RPC_S_INVALID_ARG; if (((ULONG_PTR)Buffer & 7) != 0) return RPC_X_INVALID_BUFFER; return RPC_S_OK; } /*********************************************************************** * MesEncodeFixedBufferHandleCreate [RPCRT4.@] */ RPC_STATUS RPC_ENTRY MesEncodeFixedBufferHandleCreate( char *Buffer, ULONG BufferSize, ULONG *pEncodedSize, handle_t *pHandle) { MIDL_ES_MESSAGE *pEsMsg; RPC_STATUS status; TRACE("(%p, %d, %p, %p)\n", Buffer, BufferSize, pEncodedSize, pHandle); if ((status = validate_mes_buffer_pointer(Buffer))) return status; if (!pEncodedSize) return RPC_S_INVALID_ARG; /* FIXME: check BufferSize too */ pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg)); if (!pEsMsg) return RPC_S_OUT_OF_MEMORY; init_MIDL_ES_MESSAGE(pEsMsg); pEsMsg->Operation = MES_ENCODE; pEsMsg->HandleStyle = MES_FIXED_BUFFER_HANDLE; pEsMsg->Buffer = (unsigned char *)Buffer; pEsMsg->BufferSize = BufferSize; pEsMsg->pEncodedSize = pEncodedSize; *pHandle = (handle_t)pEsMsg; return RPC_S_OK; } /*********************************************************************** * MesEncodeDynBufferHandleCreate [RPCRT4.@] */ RPC_STATUS RPC_ENTRY MesEncodeDynBufferHandleCreate(char **Buffer, ULONG *pEncodedSize, handle_t *pHandle) { MIDL_ES_MESSAGE *pEsMsg; TRACE("(%p, %p, %p)\n", Buffer, pEncodedSize, pHandle); if (!pEncodedSize) return RPC_S_INVALID_ARG; pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg)); if (!pEsMsg) return RPC_S_OUT_OF_MEMORY; init_MIDL_ES_MESSAGE(pEsMsg); pEsMsg->Operation = MES_ENCODE; pEsMsg->HandleStyle = MES_DYNAMIC_BUFFER_HANDLE; pEsMsg->pDynBuffer = (unsigned char **)Buffer; pEsMsg->pEncodedSize = pEncodedSize; *pHandle = (handle_t)pEsMsg; return RPC_S_OK; } /*********************************************************************** * MesDecodeBufferHandleCreate [RPCRT4.@] */ RPC_STATUS RPC_ENTRY MesDecodeBufferHandleCreate( char *Buffer, ULONG BufferSize, handle_t *pHandle) { MIDL_ES_MESSAGE *pEsMsg; RPC_STATUS status; TRACE("(%p, %d, %p)\n", Buffer, BufferSize, pHandle); if ((status = validate_mes_buffer_pointer(Buffer))) return status; pEsMsg = HeapAlloc(GetProcessHeap(), 0, sizeof(*pEsMsg)); if (!pEsMsg) return RPC_S_OUT_OF_MEMORY; init_MIDL_ES_MESSAGE(pEsMsg); pEsMsg->Operation = MES_DECODE; pEsMsg->HandleStyle = MES_FIXED_BUFFER_HANDLE; pEsMsg->Buffer = (unsigned char *)Buffer; pEsMsg->BufferSize = BufferSize; *pHandle = (handle_t)pEsMsg; return RPC_S_OK; } static void es_data_alloc(MIDL_ES_MESSAGE *pEsMsg, ULONG size) { if (pEsMsg->HandleStyle == MES_INCREMENTAL_HANDLE) { unsigned int tmpsize = size; TRACE("%d with incremental handle\n", size); pEsMsg->Alloc(pEsMsg->UserState, (char **)&pEsMsg->StubMsg.Buffer, &tmpsize); if (tmpsize < size) { ERR("not enough bytes allocated - requested %d, got %d\n", size, tmpsize); RpcRaiseException(RPC_S_OUT_OF_MEMORY); } } else if (pEsMsg->HandleStyle == MES_FIXED_BUFFER_HANDLE) { TRACE("%d with fixed buffer handle\n", size); pEsMsg->StubMsg.Buffer = pEsMsg->Buffer; } pEsMsg->StubMsg.RpcMsg->Buffer = pEsMsg->StubMsg.BufferStart = pEsMsg->StubMsg.Buffer; } static void es_data_read(MIDL_ES_MESSAGE *pEsMsg, ULONG size) { if (pEsMsg->HandleStyle == MES_INCREMENTAL_HANDLE) { unsigned int tmpsize = size; TRACE("%d from incremental handle\n", size); pEsMsg->Read(pEsMsg->UserState, (char **)&pEsMsg->StubMsg.Buffer, &tmpsize); if (tmpsize < size) { ERR("not enough bytes read - requested %d, got %d\n", size, tmpsize); RpcRaiseException(RPC_S_OUT_OF_MEMORY); } } else { TRACE("%d from fixed or dynamic buffer handle\n", size); /* FIXME: validate BufferSize? */ pEsMsg->StubMsg.Buffer = pEsMsg->Buffer; pEsMsg->Buffer += size; pEsMsg->BufferSize -= size; } pEsMsg->StubMsg.BufferLength = size; pEsMsg->StubMsg.RpcMsg->Buffer = pEsMsg->StubMsg.BufferStart = pEsMsg->StubMsg.Buffer; pEsMsg->StubMsg.BufferEnd = pEsMsg->StubMsg.Buffer + size; } static void es_data_write(MIDL_ES_MESSAGE *pEsMsg, ULONG size) { if (pEsMsg->HandleStyle == MES_INCREMENTAL_HANDLE) { TRACE("%d to incremental handle\n", size); pEsMsg->Write(pEsMsg->UserState, (char *)pEsMsg->StubMsg.BufferStart, size); } else { TRACE("%d to dynamic or fixed buffer handle\n", size); *pEsMsg->pEncodedSize += size; } } static inline ULONG mes_proc_header_buffer_size(void) { return 4 + 2*sizeof(RPC_SYNTAX_IDENTIFIER) + 12; } static void mes_proc_header_marshal(MIDL_ES_MESSAGE *pEsMsg) { const RPC_CLIENT_INTERFACE *client_interface = pEsMsg->StubMsg.StubDesc->RpcInterfaceInformation; *(WORD *)pEsMsg->StubMsg.Buffer = 0x0101; pEsMsg->StubMsg.Buffer += 2; *(WORD *)pEsMsg->StubMsg.Buffer = 0xcccc; pEsMsg->StubMsg.Buffer += 2; memcpy(pEsMsg->StubMsg.Buffer, &client_interface->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER)); pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER); memcpy(pEsMsg->StubMsg.Buffer, &pEsMsg->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)); pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER); *(DWORD *)pEsMsg->StubMsg.Buffer = pEsMsg->ProcNumber; pEsMsg->StubMsg.Buffer += 4; *(DWORD *)pEsMsg->StubMsg.Buffer = 0x00000001; pEsMsg->StubMsg.Buffer += 4; *(DWORD *)pEsMsg->StubMsg.Buffer = pEsMsg->ByteCount; pEsMsg->StubMsg.Buffer += 4; } static void mes_proc_header_unmarshal(MIDL_ES_MESSAGE *pEsMsg) { const RPC_CLIENT_INTERFACE *client_interface = pEsMsg->StubMsg.StubDesc->RpcInterfaceInformation; es_data_read(pEsMsg, mes_proc_header_buffer_size()); if (*(WORD *)pEsMsg->StubMsg.Buffer != 0x0101) { FIXME("unknown value at Buffer[0] 0x%04x\n", *(WORD *)pEsMsg->StubMsg.Buffer); RpcRaiseException(RPC_X_WRONG_ES_VERSION); } pEsMsg->StubMsg.Buffer += 2; if (*(WORD *)pEsMsg->StubMsg.Buffer != 0xcccc) FIXME("unknown value at Buffer[2] 0x%04x\n", *(WORD *)pEsMsg->StubMsg.Buffer); pEsMsg->StubMsg.Buffer += 2; if (memcmp(pEsMsg->StubMsg.Buffer, &client_interface->TransferSyntax, sizeof(RPC_SYNTAX_IDENTIFIER))) { const RPC_SYNTAX_IDENTIFIER *AlienTransferSyntax = (const RPC_SYNTAX_IDENTIFIER *)pEsMsg->StubMsg.Buffer; ERR("bad transfer syntax %s {%d.%d}\n", debugstr_guid(&AlienTransferSyntax->SyntaxGUID), AlienTransferSyntax->SyntaxVersion.MajorVersion, AlienTransferSyntax->SyntaxVersion.MinorVersion); RpcRaiseException(RPC_S_UNSUPPORTED_TRANS_SYN); } pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER); memcpy(&pEsMsg->InterfaceId, pEsMsg->StubMsg.Buffer, sizeof(RPC_SYNTAX_IDENTIFIER)); pEsMsg->StubMsg.Buffer += sizeof(RPC_SYNTAX_IDENTIFIER); pEsMsg->ProcNumber = *(DWORD *)pEsMsg->StubMsg.Buffer; pEsMsg->StubMsg.Buffer += 4; if (*(DWORD *)pEsMsg->StubMsg.Buffer != 0x00000001) FIXME("unknown value 0x%08x, expected 0x00000001\n", *(DWORD *)pEsMsg->StubMsg.Buffer); pEsMsg->StubMsg.Buffer += 4; pEsMsg->ByteCount = *(DWORD *)pEsMsg->StubMsg.Buffer; pEsMsg->StubMsg.Buffer += 4; if (pEsMsg->ByteCount + mes_proc_header_buffer_size() < pEsMsg->ByteCount) RpcRaiseException(RPC_S_INVALID_BOUND); } /*********************************************************************** * NdrMesProcEncodeDecode [RPCRT4.@] */ void WINAPIV NdrMesProcEncodeDecode(handle_t Handle, const MIDL_STUB_DESC * pStubDesc, PFORMAT_STRING pFormat, ...) { /* pointer to start of stack where arguments start */ RPC_MESSAGE rpcMsg; MIDL_ES_MESSAGE *pEsMsg = Handle; /* size of stack */ unsigned short stack_size; /* header for procedure string */ const NDR_PROC_HEADER *pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0]; const RPC_CLIENT_INTERFACE *client_interface; __ms_va_list args; unsigned int number_of_params; ULONG_PTR arg_buffer[256]; TRACE("Handle %p, pStubDesc %p, pFormat %p, ...\n", Handle, pStubDesc, pFormat); /* Later NDR language versions probably won't be backwards compatible */ if (pStubDesc->Version > 0x50002) { FIXME("Incompatible stub description version: 0x%x\n", pStubDesc->Version); RpcRaiseException(RPC_X_WRONG_STUB_VERSION); } client_interface = pStubDesc->RpcInterfaceInformation; pEsMsg->InterfaceId = client_interface->InterfaceId; if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) { const NDR_PROC_HEADER_RPC *header_rpc = (const NDR_PROC_HEADER_RPC *)&pFormat[0]; stack_size = header_rpc->stack_size; pEsMsg->ProcNumber = header_rpc->proc_num; pFormat += sizeof(NDR_PROC_HEADER_RPC); } else { stack_size = pProcHeader->stack_size; pEsMsg->ProcNumber = pProcHeader->proc_num; pFormat += sizeof(NDR_PROC_HEADER); } if (pProcHeader->handle_type == RPC_FC_BIND_EXPLICIT) { switch (*pFormat) /* handle_type */ { case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */ pFormat += sizeof(NDR_EHD_PRIMITIVE); break; case RPC_FC_BIND_GENERIC: /* explicit generic */ pFormat += sizeof(NDR_EHD_GENERIC); break; case RPC_FC_BIND_CONTEXT: /* explicit context */ pFormat += sizeof(NDR_EHD_CONTEXT); break; default: ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type); RpcRaiseException(RPC_X_BAD_STUB_DATA); } } TRACE("stack size: 0x%x\n", stack_size); TRACE("proc num: %d\n", pEsMsg->ProcNumber); memset(&rpcMsg, 0, sizeof(rpcMsg)); pEsMsg->StubMsg.RpcMsg = &rpcMsg; pEsMsg->StubMsg.StubDesc = pStubDesc; pEsMsg->StubMsg.pfnAllocate = pStubDesc->pfnAllocate; pEsMsg->StubMsg.pfnFree = pStubDesc->pfnFree; /* create the full pointer translation tables, if requested */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) pEsMsg->StubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT); TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags); TRACE("stubdesc version = 0x%x\n", pStubDesc->Version); TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion); /* needed for conformance of top-level objects */ __ms_va_start( args, pFormat ); pEsMsg->StubMsg.StackTop = va_arg( args, unsigned char * ); __ms_va_end( args ); pFormat = convert_old_args( &pEsMsg->StubMsg, pFormat, stack_size, FALSE, arg_buffer, sizeof(arg_buffer), &number_of_params ); switch (pEsMsg->Operation) { case MES_ENCODE: pEsMsg->StubMsg.BufferLength = mes_proc_header_buffer_size(); client_do_args( &pEsMsg->StubMsg, pFormat, STUBLESS_CALCSIZE, NULL, number_of_params, NULL ); pEsMsg->ByteCount = pEsMsg->StubMsg.BufferLength - mes_proc_header_buffer_size(); es_data_alloc(pEsMsg, pEsMsg->StubMsg.BufferLength); mes_proc_header_marshal(pEsMsg); client_do_args( &pEsMsg->StubMsg, pFormat, STUBLESS_MARSHAL, NULL, number_of_params, NULL ); es_data_write(pEsMsg, pEsMsg->ByteCount); break; case MES_DECODE: mes_proc_header_unmarshal(pEsMsg); es_data_read(pEsMsg, pEsMsg->ByteCount); client_do_args( &pEsMsg->StubMsg, pFormat, STUBLESS_UNMARSHAL, NULL, number_of_params, NULL ); break; default: RpcRaiseException(RPC_S_INTERNAL_ERROR); return; } /* free the full pointer translation tables */ if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) NdrFullPointerXlatFree(pEsMsg->StubMsg.FullPtrXlatTables); } void RPC_ENTRY NdrMesTypeDecode2(handle_t Handle, const MIDL_TYPE_PICKLING_INFO *pPicklingInfo, const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormatString, void *pObject) { FIXME("(%p, %p, %p, %p, %p)\n", Handle, pPicklingInfo, pStubDesc, pFormatString, pObject); } void RPC_ENTRY NdrMesTypeEncode2(handle_t Handle, const MIDL_TYPE_PICKLING_INFO *pPicklingInfo, const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormatString, const void *pObject) { FIXME("(%p, %p, %p, %p, %p)\n", Handle, pPicklingInfo, pStubDesc, pFormatString, pObject); } void RPC_ENTRY NdrMesTypeFree2(handle_t Handle, const MIDL_TYPE_PICKLING_INFO *pPicklingInfo, const MIDL_STUB_DESC *pStubDesc, PFORMAT_STRING pFormatString, void *pObject) { FIXME("(%p, %p, %p, %p, %p)\n", Handle, pPicklingInfo, pStubDesc, pFormatString, pObject); }