FreeRDP/winpr/libwinpr/rpc/ndr.c

352 lines
9.2 KiB
C
Raw Normal View History

/**
2012-05-05 02:32:34 +04:00
* WinPR: Windows Portable Runtime
* Network Data Representation (NDR)
*
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2012-05-05 03:36:35 +04:00
#include <stdio.h>
2012-05-06 02:42:35 +04:00
#include <stdlib.h>
#include <stdarg.h>
2012-05-05 03:36:35 +04:00
2012-05-05 02:32:34 +04:00
#include <winpr/ndr.h>
#ifndef _WIN32
#include "ndr_array.h"
#include "ndr_context.h"
#include "ndr_pointer.h"
#include "ndr_simple.h"
#include "ndr_string.h"
#include "ndr_structure.h"
#include "ndr_union.h"
#include "ndr_private.h"
2014-08-18 19:22:22 +04:00
#include "../log.h"
#define TAG WINPR_TAG("rpc")
2014-08-18 19:22:22 +04:00
/**
* MSRPC NDR Types Technical Overview:
* http://dvlabs.tippingpoint.com/blog/2007/11/24/msrpc-ndr-types/
*/
void NdrPrintParamAttributes(PARAM_ATTRIBUTES attributes)
{
if (attributes.ServerAllocSize)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "ServerAllocSize, ");
if (attributes.SaveForAsyncFinish)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "SaveForAsyncFinish, ");
if (attributes.IsDontCallFreeInst)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsDontCallFreeInst, ");
if (attributes.IsSimpleRef)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsSimpleRef, ");
if (attributes.IsByValue)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsByValue, ");
if (attributes.IsBasetype)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsBaseType, ");
if (attributes.IsReturn)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsReturn, ");
if (attributes.IsOut)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsOut, ");
if (attributes.IsIn)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsIn, ");
if (attributes.IsPipe)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "IsPipe, ");
if (attributes.MustFree)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "MustFree, ");
if (attributes.MustSize)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "MustSize, ");
2012-04-29 07:37:07 +04:00
}
2014-08-18 21:34:47 +04:00
void NdrProcessParam(PMIDL_STUB_MESSAGE pStubMsg, NDR_PHASE phase, unsigned char* pMemory, NDR_PARAM* param)
{
unsigned char type;
PFORMAT_STRING pFormat;
/* Parameter Descriptors: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374362/ */
if (param->Attributes.IsBasetype)
{
pFormat = &param->Type.FormatChar;
if (param->Attributes.IsSimpleRef)
2014-08-18 21:34:47 +04:00
pMemory = *(unsigned char**) pMemory;
}
else
{
pFormat = &pStubMsg->StubDesc->pFormatTypes[param->Type.Offset];
if (!(param->Attributes.IsByValue))
2014-08-18 21:34:47 +04:00
pMemory = *(unsigned char**) pMemory;
}
type = (pFormat[0] & 0x7F);
if (type > FC_PAD)
return;
if (phase == NDR_PHASE_SIZE)
{
NDR_TYPE_SIZE_ROUTINE pfnSizeRoutine = pfnSizeRoutines[type];
if (pfnSizeRoutine)
pfnSizeRoutine(pStubMsg, pMemory, pFormat);
}
else if (phase == NDR_PHASE_MARSHALL)
{
NDR_TYPE_MARSHALL_ROUTINE pfnMarshallRoutine = pfnMarshallRoutines[type];
if (pfnMarshallRoutine)
pfnMarshallRoutine(pStubMsg, pMemory, *pFormat);
}
else if (phase == NDR_PHASE_UNMARSHALL)
{
NDR_TYPE_UNMARSHALL_ROUTINE pfnUnmarshallRoutine = pfnUnmarshallRoutines[type];
if (pfnUnmarshallRoutine)
pfnUnmarshallRoutine(pStubMsg, pMemory, *pFormat);
}
else if (phase == NDR_PHASE_FREE)
{
NDR_TYPE_FREE_ROUTINE pfnFreeRoutine = pfnFreeRoutines[type];
if (pfnFreeRoutine)
pfnFreeRoutine(pStubMsg, pMemory, pFormat);
}
}
2014-08-18 21:34:47 +04:00
void NdrProcessParams(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, NDR_PHASE phase, void** fpuArgs, unsigned short numberParams)
2012-04-29 07:37:07 +04:00
{
unsigned int i;
2014-08-18 21:34:47 +04:00
NDR_PARAM* params;
2012-04-29 07:37:07 +04:00
PFORMAT_STRING fmt;
2014-08-18 21:34:47 +04:00
unsigned char* arg;
unsigned char type;
2014-08-18 21:34:47 +04:00
params = (NDR_PARAM*) pFormat;
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "Params = ");
2012-04-29 07:37:07 +04:00
for (i = 0; i < numberParams; i++)
{
2013-08-29 12:05:42 +04:00
#ifdef __x86_64__
float tmp;
#endif
2012-04-29 07:37:07 +04:00
arg = pStubMsg->StackTop + params[i].StackOffset;
fmt = (PFORMAT_STRING) &pStubMsg->StubDesc->pFormatTypes[params[i].Type.Offset];
#ifdef __x86_64__
2014-08-18 19:22:22 +04:00
if ((params[i].Attributes.IsBasetype) &&
!(params[i].Attributes.IsSimpleRef) &&
((params[i].Type.FormatChar) == FC_FLOAT) && !fpuArgs)
{
2014-08-18 21:34:47 +04:00
tmp = *(double*) arg;
arg = (unsigned char*) &tmp;
}
2012-04-29 07:37:07 +04:00
2014-08-18 19:22:22 +04:00
#endif
type = (params[i].Attributes.IsBasetype) ? params[i].Type.FormatChar : *fmt;
WLog_INFO(TAG, "'\t#%u\ttype %s (0x%02X) ", i, FC_TYPE_STRINGS[type], type);
NdrPrintParamAttributes(params[i].Attributes);
2012-04-29 07:37:07 +04:00
if (params[i].Attributes.IsIn)
2012-04-29 07:37:07 +04:00
{
NdrProcessParam(pStubMsg, phase, arg, &params[i]);
2012-04-29 07:37:07 +04:00
}
}
}
void NdrClientInitializeNew(PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg,
2014-08-18 19:22:22 +04:00
PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum)
{
2012-04-29 07:37:07 +04:00
pRpcMessage->Handle = NULL;
pRpcMessage->RpcFlags = 0;
pRpcMessage->ProcNum = ProcNum;
pRpcMessage->DataRepresentation = 0;
pRpcMessage->ReservedForRuntime = NULL;
pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation;
pStubMsg->RpcMsg = pRpcMessage;
pStubMsg->BufferStart = NULL;
pStubMsg->BufferEnd = NULL;
pStubMsg->BufferLength = 0;
pStubMsg->StackTop = NULL;
pStubMsg->StubDesc = pStubDesc;
pStubMsg->IgnoreEmbeddedPointers = 0;
pStubMsg->PointerLength = 0;
2012-04-29 07:37:07 +04:00
}
void NdrPrintOptFlags(INTERPRETER_OPT_FLAGS optFlags)
{
if (optFlags.ClientMustSize)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "ClientMustSize, ");
if (optFlags.ServerMustSize)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "ServerMustSize, ");
if (optFlags.HasAsyncUuid)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasAsyncUiid, ");
if (optFlags.HasAsyncHandle)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasAsyncHandle, ");
if (optFlags.HasReturn)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasReturn, ");
if (optFlags.HasPipes)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasPipes, ");
if (optFlags.HasExtensions)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasExtensions, ");
}
void NdrPrintExtFlags(INTERPRETER_OPT_FLAGS2 extFlags)
{
if (extFlags.HasNewCorrDesc)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasNewCorrDesc, ");
if (extFlags.ClientCorrCheck)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "ClientCorrCheck, ");
if (extFlags.ServerCorrCheck)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "ServerCorrCheck, ");
if (extFlags.HasNotify)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasNotify, ");
if (extFlags.HasNotify2)
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "HasNotify2, ");
}
2014-08-18 21:34:47 +04:00
CLIENT_CALL_RETURN NdrClientCall(PMIDL_STUB_DESC pStubDescriptor, PFORMAT_STRING pFormat, void** stackTop, void** fpuStack)
2012-04-29 07:37:07 +04:00
{
RPC_MESSAGE rpcMsg;
unsigned short procNum;
unsigned short stackSize;
unsigned char numberParams;
unsigned char handleType;
2012-04-29 07:37:07 +04:00
MIDL_STUB_MESSAGE stubMsg;
INTERPRETER_FLAGS flags;
INTERPRETER_OPT_FLAGS optFlags;
2014-08-18 21:34:47 +04:00
NDR_PROC_HEADER* procHeader;
NDR_OI2_PROC_HEADER* oi2ProcHeader;
CLIENT_CALL_RETURN client_call_return;
procNum = stackSize = numberParams = 0;
2014-08-18 21:34:47 +04:00
procHeader = (NDR_PROC_HEADER*) &pFormat[0];
client_call_return.Pointer = NULL;
handleType = procHeader->HandleType;
flags = procHeader->OldOiFlags;
procNum = procHeader->ProcNum;
stackSize = procHeader->StackSize;
pFormat += sizeof(NDR_PROC_HEADER);
/* The Header: http://msdn.microsoft.com/en-us/library/windows/desktop/aa378707/ */
/* Procedure Header Descriptor: http://msdn.microsoft.com/en-us/library/windows/desktop/aa374387/ */
/* Handles: http://msdn.microsoft.com/en-us/library/windows/desktop/aa373932/ */
WLog_DBG(TAG, "Oi Header: HandleType: 0x%02X OiFlags: 0x%02X ProcNum: %hu StackSize: 0x%04X",
2014-08-18 21:34:47 +04:00
handleType, *((unsigned char*) &flags),
procNum, stackSize);
if (handleType > 0)
{
/* implicit handle */
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "Implicit Handle");
2014-08-18 21:34:47 +04:00
oi2ProcHeader = (NDR_OI2_PROC_HEADER*) &pFormat[0];
pFormat += sizeof(NDR_OI2_PROC_HEADER);
}
else
{
/* explicit handle */
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "Explicit Handle");
2014-08-18 21:34:47 +04:00
oi2ProcHeader = (NDR_OI2_PROC_HEADER*) &pFormat[6];
pFormat += sizeof(NDR_OI2_PROC_HEADER) + 6;
}
optFlags = oi2ProcHeader->Oi2Flags;
numberParams = oi2ProcHeader->NumberParams;
WLog_DBG(TAG, "Oi2 Header: Oi2Flags: 0x%02X, NumberParams: %u ClientBufferSize: %hu ServerBufferSize: %hu",
2014-08-18 21:34:47 +04:00
*((unsigned char*) &optFlags),
numberParams,
2014-08-18 19:22:22 +04:00
oi2ProcHeader->ClientBufferSize,
oi2ProcHeader->ServerBufferSize);
WLog_INFO(TAG, "Oi2Flags: ");
NdrPrintOptFlags(optFlags);
NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDescriptor, procNum);
if (optFlags.HasExtensions)
{
INTERPRETER_OPT_FLAGS2 extFlags;
2014-08-18 21:34:47 +04:00
NDR_PROC_HEADER_EXTS* extensions = (NDR_PROC_HEADER_EXTS*) pFormat;
pFormat += extensions->Size;
extFlags = extensions->Flags2;
WLog_DBG(TAG, "Extensions: Size: %hhu, flags2: 0x%02X",
2014-08-18 21:34:47 +04:00
extensions->Size, *((unsigned char*) &extensions->Flags2));
#ifdef __x86_64__
2014-08-18 19:22:22 +04:00
if (extensions->Size > sizeof(*extensions) && fpuStack)
{
int i;
2014-08-18 21:34:47 +04:00
unsigned short fpuMask = *(unsigned short*)(extensions + 1);
for (i = 0; i < 4; i++, fpuMask >>= 2)
{
switch (fpuMask & 3)
{
2014-08-18 19:22:22 +04:00
case 1:
2014-08-18 21:34:47 +04:00
*(float*) &stackTop[i] = *(float*) &fpuStack[i];
break;
2014-08-18 19:22:22 +04:00
case 2:
2014-08-18 21:34:47 +04:00
*(double*) &stackTop[i] = *(double*) &fpuStack[i];
break;
}
}
}
2014-08-18 19:22:22 +04:00
#endif
2014-08-18 19:22:22 +04:00
WLog_INFO(TAG, "ExtFlags: ");
NdrPrintExtFlags(extFlags);
}
2014-08-18 21:34:47 +04:00
stubMsg.StackTop = (unsigned char*) stackTop;
NdrProcessParams(&stubMsg, pFormat, NDR_PHASE_SIZE, fpuStack, numberParams);
WLog_DBG(TAG, "stubMsg BufferLength: %"PRIu32"", stubMsg.BufferLength);
2012-04-29 07:37:07 +04:00
return client_call_return;
}
CLIENT_CALL_RETURN NdrClientCall2(PMIDL_STUB_DESC pStubDescriptor, PFORMAT_STRING pFormat, ...)
{
va_list args;
CLIENT_CALL_RETURN client_call_return;
va_start(args, pFormat);
2014-08-18 21:34:47 +04:00
client_call_return = NdrClientCall(pStubDescriptor, pFormat, va_arg(args, void**), NULL);
2012-04-29 07:37:07 +04:00
va_end(args);
return client_call_return;
}
#endif