diff --git a/reactos/dll/win32/rpcrt4_new/cproxy.c b/reactos/dll/win32/rpcrt4_new/cproxy.c new file mode 100644 index 00000000000..6580bcf143c --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/cproxy.c @@ -0,0 +1,450 @@ +/* + * COM proxy implementation + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + * + * TODO: Handle non-i386 architectures + */ + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" +#include "rpcproxy.h" + +#include "cpsf.h" +#include "ndr_misc.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +struct StublessThunk; + +/* I don't know what MS's std proxy structure looks like, + so this probably doesn't match, but that shouldn't matter */ +typedef struct { + const IRpcProxyBufferVtbl *lpVtbl; + LPVOID *PVtbl; + LONG RefCount; + const MIDL_STUBLESS_PROXY_INFO *stubless; + const IID* piid; + LPUNKNOWN pUnkOuter; + PCInterfaceName name; + LPPSFACTORYBUFFER pPSFactory; + LPRPCCHANNELBUFFER pChannel; + struct StublessThunk *thunks; +} StdProxyImpl; + +static const IRpcProxyBufferVtbl StdProxy_Vtbl; + +#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) + +/* How the Windows stubless proxy thunks work is explained at + * http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, + * but I'll use a slightly different method, to make life easier */ + +#if defined(__i386__) + +#include "pshpack1.h" + +struct StublessThunk { + BYTE push; + DWORD index; + BYTE call; + LONG handler; + BYTE ret; + WORD bytes; + BYTE pad[3]; +}; + +#include "poppack.h" + +/* adjust the stack size since we don't use Windows's method */ +#define STACK_ADJUST sizeof(DWORD) + +#define FILL_STUBLESS(x,idx,stk) \ + x->push = 0x68; /* pushl [immediate] */ \ + x->index = (idx); \ + x->call = 0xe8; /* call [near] */ \ + x->handler = (char*)ObjectStubless - (char*)&x->ret; \ + x->ret = 0xc2; /* ret [immediate] */ \ + x->bytes = stk; \ + x->pad[0] = 0x8d; /* leal (%esi),%esi */ \ + x->pad[1] = 0x76; \ + x->pad[2] = 0x00; + +static HRESULT WINAPI ObjectStubless(DWORD index) +{ + char *args = (char*)(&index + 2); + LPVOID iface = *(LPVOID*)args; + + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + + PFORMAT_STRING fs = This->stubless->ProcFormatString + This->stubless->FormatStringOffset[index]; + unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; + TRACE("(%p)->(%d)([%d bytes]) ret=%08x\n", iface, index, bytes, *(DWORD*)(args+bytes)); + + return NdrClientCall2(This->stubless->pStubDesc, fs, args); +} + +#else /* __i386__ */ + +/* can't do that on this arch */ +struct StublessThunk { int dummy; }; +#define FILL_STUBLESS(x,idx,stk) \ + ERR("stubless proxies are not supported on this architecture\n"); +#define STACK_ADJUST 0 + +#endif /* __i386__ */ + +HRESULT WINAPI StdProxy_Construct(REFIID riid, + LPUNKNOWN pUnkOuter, + const ProxyFileInfo *ProxyInfo, + int Index, + LPPSFACTORYBUFFER pPSFactory, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj) +{ + StdProxyImpl *This; + const MIDL_STUBLESS_PROXY_INFO *stubless = NULL; + PCInterfaceName name = ProxyInfo->pNamesArray[Index]; + CInterfaceProxyVtbl *vtbl = ProxyInfo->pProxyVtblList[Index]; + + TRACE("(%p,%p,%p,%p,%p) %s\n", pUnkOuter, vtbl, pPSFactory, ppProxy, ppvObj, name); + + /* TableVersion = 2 means it is the stubless version of CInterfaceProxyVtbl */ + if (ProxyInfo->TableVersion > 1) { + stubless = *(const void **)vtbl; + vtbl = (CInterfaceProxyVtbl *)((const void **)vtbl + 1); + TRACE("stubless=%p\n", stubless); + } + + TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); + TRACE("vtbl=%p\n", vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) { + ERR("IID mismatch during proxy creation\n"); + return RPC_E_UNEXPECTED; + } + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(StdProxyImpl)); + if (!This) return E_OUTOFMEMORY; + + if (stubless) { + CInterfaceStubVtbl *svtbl = ProxyInfo->pStubVtblList[Index]; + unsigned long i, count = svtbl->header.DispatchTableCount; + /* Maybe the original vtbl is just modified directly to point at + * ObjectStublessClientXXX thunks in real Windows, but I don't like it + */ + TRACE("stubless thunks: count=%ld\n", count); + This->thunks = HeapAlloc(GetProcessHeap(),0,sizeof(struct StublessThunk)*count); + This->PVtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)*count); + for (i=0; ithunks[i]; + if (vtbl->Vtbl[i] == (LPVOID)-1) { + PFORMAT_STRING fs = stubless->ProcFormatString + stubless->FormatStringOffset[i]; + unsigned bytes = *(const WORD*)(fs+8) - STACK_ADJUST; + TRACE("method %ld: stacksize=%d\n", i, bytes); + FILL_STUBLESS(thunk, i, bytes) + This->PVtbl[i] = thunk; + } + else { + memset(thunk, 0, sizeof(struct StublessThunk)); + This->PVtbl[i] = vtbl->Vtbl[i]; + } + } + } + else + This->PVtbl = vtbl->Vtbl; + + This->lpVtbl = &StdProxy_Vtbl; + /* one reference for the proxy */ + This->RefCount = 1; + This->stubless = stubless; + This->piid = vtbl->header.piid; + This->pUnkOuter = pUnkOuter; + This->name = name; + This->pPSFactory = pPSFactory; + This->pChannel = NULL; + *ppProxy = (LPRPCPROXYBUFFER)&This->lpVtbl; + *ppvObj = &This->PVtbl; + /* if there is no outer unknown then the caller will control the lifetime + * of the proxy object through the proxy buffer, so no need to increment the + * ref count of the proxy object */ + if (pUnkOuter) + IUnknown_AddRef((IUnknown *)*ppvObj); + IPSFactoryBuffer_AddRef(pPSFactory); + + return S_OK; +} + +static void WINAPI StdProxy_Destruct(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + + if (This->pChannel) + IRpcProxyBuffer_Disconnect(iface); + + IPSFactoryBuffer_Release(This->pPSFactory); + if (This->thunks) { + HeapFree(GetProcessHeap(),0,This->PVtbl); + HeapFree(GetProcessHeap(),0,This->thunks); + } + HeapFree(GetProcessHeap(),0,This); +} + +static HRESULT WINAPI StdProxy_QueryInterface(LPRPCPROXYBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); + + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(This->piid,riid)) { + *obj = &This->PVtbl; + InterlockedIncrement(&This->RefCount); + return S_OK; + } + + if (IsEqualGUID(&IID_IRpcProxyBuffer,riid)) { + *obj = &This->lpVtbl; + InterlockedIncrement(&This->RefCount); + return S_OK; + } + + return E_NOINTERFACE; +} + +static ULONG WINAPI StdProxy_AddRef(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->AddRef()\n",This); + + return InterlockedIncrement(&This->RefCount); +} + +static ULONG WINAPI StdProxy_Release(LPRPCPROXYBUFFER iface) +{ + ULONG refs; + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Release()\n",This); + + refs = InterlockedDecrement(&This->RefCount); + if (!refs) + StdProxy_Destruct((LPRPCPROXYBUFFER)&This->lpVtbl); + return refs; +} + +static HRESULT WINAPI StdProxy_Connect(LPRPCPROXYBUFFER iface, + LPRPCCHANNELBUFFER pChannel) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Connect(%p)\n",This,pChannel); + + This->pChannel = pChannel; + IRpcChannelBuffer_AddRef(pChannel); + return S_OK; +} + +static VOID WINAPI StdProxy_Disconnect(LPRPCPROXYBUFFER iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,lpVtbl,iface); + TRACE("(%p)->Disconnect()\n",This); + + IRpcChannelBuffer_Release(This->pChannel); + This->pChannel = NULL; +} + +static const IRpcProxyBufferVtbl StdProxy_Vtbl = +{ + StdProxy_QueryInterface, + StdProxy_AddRef, + StdProxy_Release, + StdProxy_Connect, + StdProxy_Disconnect +}; + +static void StdProxy_GetChannel(LPVOID iface, + LPRPCCHANNELBUFFER *ppChannel) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->GetChannel(%p) %s\n",This,ppChannel,This->name); + + *ppChannel = This->pChannel; +} + +static void StdProxy_GetIID(LPVOID iface, + const IID **ppiid) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->GetIID(%p) %s\n",This,ppiid,This->name); + + *ppiid = This->piid; +} + +HRESULT WINAPI IUnknown_QueryInterface_Proxy(LPUNKNOWN iface, + REFIID riid, + LPVOID *ppvObj) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->QueryInterface(%s,%p) %s\n",This,debugstr_guid(riid),ppvObj,This->name); + return IUnknown_QueryInterface(This->pUnkOuter,riid,ppvObj); +} + +ULONG WINAPI IUnknown_AddRef_Proxy(LPUNKNOWN iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->AddRef() %s\n",This,This->name); + return IUnknown_AddRef(This->pUnkOuter); +} + +ULONG WINAPI IUnknown_Release_Proxy(LPUNKNOWN iface) +{ + ICOM_THIS_MULTI(StdProxyImpl,PVtbl,iface); + TRACE("(%p)->Release() %s\n",This,This->name); + return IUnknown_Release(This->pUnkOuter); +} + +/*********************************************************************** + * NdrProxyInitialize [RPCRT4.@] + */ +void WINAPI NdrProxyInitialize(void *This, + PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + unsigned int ProcNum) +{ + TRACE("(%p,%p,%p,%p,%d)\n", This, pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + NdrClientInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor, ProcNum); + StdProxy_GetChannel(This, &pStubMsg->pRpcChannelBuffer); + IRpcChannelBuffer_GetDestCtx(pStubMsg->pRpcChannelBuffer, + &pStubMsg->dwDestContext, + &pStubMsg->pvDestContext); + TRACE("channel=%p\n", pStubMsg->pRpcChannelBuffer); +} + +/*********************************************************************** + * NdrProxyGetBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyGetBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + const IID *riid = NULL; + + TRACE("(%p,%p)\n", This, pStubMsg); + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + pStubMsg->dwStubPhase = PROXY_GETBUFFER; + StdProxy_GetIID(This, &riid); + hr = IRpcChannelBuffer_GetBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + riid); + if (FAILED(hr)) + { + RpcRaiseException(hr); + return; + } + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + pStubMsg->dwStubPhase = PROXY_MARSHAL; +} + +/*********************************************************************** + * NdrProxySendReceive [RPCRT4.@] + */ +void WINAPI NdrProxySendReceive(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + ULONG Status = 0; + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + + if (!pStubMsg->pRpcChannelBuffer) + { + WARN("Trying to use disconnected proxy %p\n", This); + RpcRaiseException(RPC_E_DISCONNECTED); + } + + pStubMsg->dwStubPhase = PROXY_SENDRECEIVE; + hr = IRpcChannelBuffer_SendReceive(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg, + &Status); + pStubMsg->dwStubPhase = PROXY_UNMARSHAL; + pStubMsg->BufferLength = pStubMsg->RpcMsg->BufferLength; + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; + + /* raise exception if call failed */ + if (hr == RPC_S_CALL_FAILED) RpcRaiseException(*(DWORD*)pStubMsg->Buffer); + else if (FAILED(hr)) RpcRaiseException(hr); +} + +/*********************************************************************** + * NdrProxyFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrProxyFreeBuffer(void *This, + PMIDL_STUB_MESSAGE pStubMsg) +{ + HRESULT hr; + + TRACE("(%p,%p)\n", This, pStubMsg); + hr = IRpcChannelBuffer_FreeBuffer(pStubMsg->pRpcChannelBuffer, + (RPCOLEMESSAGE*)pStubMsg->RpcMsg); +} + +/*********************************************************************** + * NdrProxyErrorHandler [RPCRT4.@] + */ +HRESULT WINAPI NdrProxyErrorHandler(DWORD dwExceptionCode) +{ + WARN("(0x%08x): a proxy call failed\n", dwExceptionCode); + + if (FAILED(dwExceptionCode)) + return dwExceptionCode; + else + return HRESULT_FROM_WIN32(dwExceptionCode); +} + +HRESULT WINAPI +CreateProxyFromTypeInfo( LPTYPEINFO pTypeInfo, LPUNKNOWN pUnkOuter, REFIID riid, + LPRPCPROXYBUFFER *ppProxy, LPVOID *ppv ) +{ + typedef INT (WINAPI *MessageBoxA)(HWND,LPCSTR,LPCSTR,UINT); + HMODULE hUser32 = LoadLibraryA("user32"); + MessageBoxA pMessageBoxA = (void *)GetProcAddress(hUser32, "MessageBoxA"); + + FIXME("%p %p %s %p %p\n", pTypeInfo, pUnkOuter, debugstr_guid(riid), ppProxy, ppv); + if (pMessageBoxA) + { + pMessageBoxA(NULL, + "The native implementation of OLEAUT32.DLL cannot be used " + "with Wine's RPCRT4.DLL. Remove OLEAUT32.DLL and try again.\n", + "Wine: Unimplemented CreateProxyFromTypeInfo", + 0x10); + ExitProcess(1); + } + return E_NOTIMPL; +} diff --git a/reactos/dll/win32/rpcrt4_new/cpsf.c b/reactos/dll/win32/rpcrt4_new/cpsf.c new file mode 100644 index 00000000000..dcf37219195 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/cpsf.c @@ -0,0 +1,307 @@ +/* + * COM proxy/stub factory (CStdPSFactory) implementation + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "winreg.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "cpsf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static BOOL FindProxyInfo(const ProxyFileInfo **pProxyFileList, REFIID riid, const ProxyFileInfo **pProxyInfo, int *pIndex) +{ + while (*pProxyFileList) { + if ((*pProxyFileList)->pIIDLookupRtn(riid, pIndex)) { + *pProxyInfo = *pProxyFileList; + TRACE("found: ProxyInfo %p Index %d\n", *pProxyInfo, *pIndex); + return TRUE; + } + pProxyFileList++; + } + TRACE("not found\n"); + return FALSE; +} + +static HRESULT WINAPI CStdPSFactory_QueryInterface(LPPSFACTORYBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->QueryInterface(%s,%p)\n",iface,debugstr_guid(riid),obj); + if (IsEqualGUID(&IID_IUnknown,riid) || + IsEqualGUID(&IID_IPSFactoryBuffer,riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI CStdPSFactory_AddRef(LPPSFACTORYBUFFER iface) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->AddRef()\n",iface); + return ++(This->RefCount); +} + +static ULONG WINAPI CStdPSFactory_Release(LPPSFACTORYBUFFER iface) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + TRACE("(%p)->Release()\n",iface); + return --(This->RefCount); +} + +static HRESULT WINAPI CStdPSFactory_CreateProxy(LPPSFACTORYBUFFER iface, + LPUNKNOWN pUnkOuter, + REFIID riid, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppv) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + const ProxyFileInfo *ProxyInfo; + int Index; + TRACE("(%p)->CreateProxy(%p,%s,%p,%p)\n",iface,pUnkOuter, + debugstr_guid(riid),ppProxy,ppv); + if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) + return E_NOINTERFACE; + return StdProxy_Construct(riid, pUnkOuter, ProxyInfo, Index, iface, ppProxy, ppv); +} + +static HRESULT WINAPI CStdPSFactory_CreateStub(LPPSFACTORYBUFFER iface, + REFIID riid, + LPUNKNOWN pUnkServer, + LPRPCSTUBBUFFER *ppStub) +{ + CStdPSFactoryBuffer *This = (CStdPSFactoryBuffer *)iface; + const ProxyFileInfo *ProxyInfo; + int Index; + TRACE("(%p)->CreateStub(%s,%p,%p)\n",iface,debugstr_guid(riid), + pUnkServer,ppStub); + if (!FindProxyInfo(This->pProxyFileList,riid,&ProxyInfo,&Index)) + return E_NOINTERFACE; + + if(ProxyInfo->pDelegatedIIDs && ProxyInfo->pDelegatedIIDs[Index]) + return CStdStubBuffer_Delegating_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], + ProxyInfo->pStubVtblList[Index], ProxyInfo->pDelegatedIIDs[Index], + iface, ppStub); + + return CStdStubBuffer_Construct(riid, pUnkServer, ProxyInfo->pNamesArray[Index], + ProxyInfo->pStubVtblList[Index], iface, ppStub); +} + +static const IPSFactoryBufferVtbl CStdPSFactory_Vtbl = +{ + CStdPSFactory_QueryInterface, + CStdPSFactory_AddRef, + CStdPSFactory_Release, + CStdPSFactory_CreateProxy, + CStdPSFactory_CreateStub +}; + +/*********************************************************************** + * NdrDllGetClassObject [RPCRT4.@] + */ +HRESULT WINAPI NdrDllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid, + CStdPSFactoryBuffer *pPSFactoryBuffer) +{ + TRACE("(%s, %s, %p, %p, %s, %p)\n", debugstr_guid(rclsid), + debugstr_guid(iid), ppv, pProxyFileList, debugstr_guid(pclsid), + pPSFactoryBuffer); + + *ppv = NULL; + if (!pPSFactoryBuffer->lpVtbl) { + const ProxyFileInfo **pProxyFileList2; + int max_delegating_vtbl_size = 0; + pPSFactoryBuffer->lpVtbl = &CStdPSFactory_Vtbl; + pPSFactoryBuffer->RefCount = 0; + pPSFactoryBuffer->pProxyFileList = pProxyFileList; + for (pProxyFileList2 = pProxyFileList; *pProxyFileList2; pProxyFileList2++) { + int i; + for (i = 0; i < (*pProxyFileList2)->TableSize; i++) { + /* FIXME: i think that different vtables should be copied for + * async interfaces */ + void * const *pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Vtbl; + void **pRpcStubVtbl = (void **)&(*pProxyFileList2)->pStubVtblList[i]->Vtbl; + int j; + + if ((*pProxyFileList2)->pDelegatedIIDs && (*pProxyFileList2)->pDelegatedIIDs[i]) { + pSrcRpcStubVtbl = (void * const *)&CStdStubBuffer_Delegating_Vtbl; + if ((*pProxyFileList2)->pStubVtblList[i]->header.DispatchTableCount > max_delegating_vtbl_size) + max_delegating_vtbl_size = (*pProxyFileList2)->pStubVtblList[i]->header.DispatchTableCount; + } + + for (j = 0; j < sizeof(IRpcStubBufferVtbl)/sizeof(void *); j++) + if (!pRpcStubVtbl[j]) + pRpcStubVtbl[j] = pSrcRpcStubVtbl[j]; + } + } + if(max_delegating_vtbl_size > 0) + create_delegating_vtbl(max_delegating_vtbl_size); + } + if (IsEqualGUID(rclsid, pclsid)) + return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); + else { + const ProxyFileInfo *info; + int index; + /* otherwise, the dll may be using the iid as the clsid, so + * search for it in the proxy file list */ + if (FindProxyInfo(pProxyFileList, rclsid, &info, &index)) + return IPSFactoryBuffer_QueryInterface((LPPSFACTORYBUFFER)pPSFactoryBuffer, iid, ppv); + + WARN("class %s not available\n", debugstr_guid(rclsid)); + return CLASS_E_CLASSNOTAVAILABLE; + } +} + +/*********************************************************************** + * NdrDllCanUnloadNow [RPCRT4.@] + */ +HRESULT WINAPI NdrDllCanUnloadNow(CStdPSFactoryBuffer *pPSFactoryBuffer) +{ + return !(pPSFactoryBuffer->RefCount); +} + +/*********************************************************************** + * NdrDllRegisterProxy [RPCRT4.@] + */ +HRESULT WINAPI NdrDllRegisterProxy(HMODULE hDll, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid) +{ + LPSTR clsid; + char keyname[120], module[MAX_PATH]; + HKEY key, subkey; + DWORD len; + + TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); + UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); + + /* register interfaces to point to clsid */ + while (*pProxyFileList) { + unsigned u; + for (u=0; u<(*pProxyFileList)->TableSize; u++) { + CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; + PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; + LPSTR iid; + + TRACE("registering %s %s => %s\n", name, debugstr_guid(proxy->header.piid), clsid); + + UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); + snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); + RpcStringFreeA((unsigned char**)&iid); + if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { + if (name) + RegSetValueExA(key, NULL, 0, REG_SZ, (const BYTE *)name, strlen(name)); + if (RegCreateKeyExA(key, "ProxyStubClsid32", 0, NULL, 0, + KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { + snprintf(module, sizeof(module), "{%s}", clsid); + RegSetValueExA(subkey, NULL, 0, REG_SZ, (LPBYTE)module, strlen(module)); + RegCloseKey(subkey); + } + RegCloseKey(key); + } + } + pProxyFileList++; + } + + /* register clsid to point to module */ + snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); + len = GetModuleFileNameA(hDll, module, sizeof(module)); + if (len && len < sizeof(module)) { + TRACE("registering CLSID %s => %s\n", clsid, module); + if (RegCreateKeyExA(HKEY_CLASSES_ROOT, keyname, 0, NULL, 0, + KEY_WRITE, NULL, &key, NULL) == ERROR_SUCCESS) { + RegSetValueExA(subkey, NULL, 0, REG_SZ, (const BYTE *)"PSFactoryBuffer", strlen("PSFactoryBuffer")); + if (RegCreateKeyExA(key, "InProcServer32", 0, NULL, 0, + KEY_WRITE, NULL, &subkey, NULL) == ERROR_SUCCESS) { + RegSetValueExA(subkey, NULL, 0, REG_SZ, (LPBYTE)module, strlen(module)); + RegSetValueExA(subkey, "ThreadingModel", 0, REG_SZ, (const BYTE *)"Both", strlen("Both")); + RegCloseKey(subkey); + } + RegCloseKey(key); + } + } + + /* done */ + RpcStringFreeA((unsigned char**)&clsid); + return S_OK; +} + +/*********************************************************************** + * NdrDllUnregisterProxy [RPCRT4.@] + */ +HRESULT WINAPI NdrDllUnregisterProxy(HMODULE hDll, + const ProxyFileInfo **pProxyFileList, + const CLSID *pclsid) +{ + LPSTR clsid; + char keyname[120], module[MAX_PATH]; + DWORD len; + + TRACE("(%p,%p,%s)\n", hDll, pProxyFileList, debugstr_guid(pclsid)); + UuidToStringA((UUID*)pclsid, (unsigned char**)&clsid); + + /* unregister interfaces */ + while (*pProxyFileList) { + unsigned u; + for (u=0; u<(*pProxyFileList)->TableSize; u++) { + CInterfaceStubVtbl *proxy = (*pProxyFileList)->pStubVtblList[u]; + PCInterfaceName name = (*pProxyFileList)->pNamesArray[u]; + LPSTR iid; + + TRACE("unregistering %s %s <= %s\n", name, debugstr_guid(proxy->header.piid), clsid); + + UuidToStringA((UUID*)proxy->header.piid, (unsigned char**)&iid); + snprintf(keyname, sizeof(keyname), "Interface\\{%s}", iid); + RpcStringFreeA((unsigned char**)&iid); + RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); + } + pProxyFileList++; + } + + /* unregister clsid */ + snprintf(keyname, sizeof(keyname), "CLSID\\{%s}", clsid); + len = GetModuleFileNameA(hDll, module, sizeof(module)); + if (len && len < sizeof(module)) { + TRACE("unregistering CLSID %s <= %s\n", clsid, module); + RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname); + } + + /* done */ + RpcStringFreeA((unsigned char**)&clsid); + return S_OK; +} diff --git a/reactos/dll/win32/rpcrt4_new/cpsf.h b/reactos/dll/win32/rpcrt4_new/cpsf.h new file mode 100644 index 00000000000..5ce8fe6575e --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/cpsf.h @@ -0,0 +1,56 @@ +/* + * COM proxy definitions + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + */ + +#ifndef __WINE_CPSF_H +#define __WINE_CPSF_H + +HRESULT WINAPI StdProxy_Construct(REFIID riid, + LPUNKNOWN pUnkOuter, + const ProxyFileInfo *ProxyInfo, + int Index, + LPPSFACTORYBUFFER pPSFactory, + LPRPCPROXYBUFFER *ppProxy, + LPVOID *ppvObj); + +HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub); + +HRESULT WINAPI CStdStubBuffer_Delegating_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + REFIID delegating_iid, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub); + +const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface); + +const IRpcStubBufferVtbl CStdStubBuffer_Vtbl; +const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl; + +void create_delegating_vtbl(DWORD num_methods); + +HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub); + +#endif /* __WINE_CPSF_H */ diff --git a/reactos/dll/win32/rpcrt4_new/cstub.c b/reactos/dll/win32/rpcrt4_new/cstub.c new file mode 100644 index 00000000000..0ae85ae055f --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/cstub.c @@ -0,0 +1,587 @@ +/* + * COM stub (CStdStubBuffer) implementation + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "excpt.h" + +#include "objbase.h" +#include "rpcproxy.h" + +#include "wine/debug.h" +#include "wine/exception.h" + +#include "cpsf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#define STUB_HEADER(This) (((const CInterfaceStubHeader*)((This)->lpVtbl))[-1]) + +static WINE_EXCEPTION_FILTER(stub_filter) +{ + if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) + return EXCEPTION_CONTINUE_SEARCH; + return EXCEPTION_EXECUTE_HANDLER; +} + +typedef struct +{ + IUnknownVtbl *base_obj; + IRpcStubBuffer *base_stub; + CStdStubBuffer stub_buffer; +} cstdstubbuffer_delegating_t; + +static inline cstdstubbuffer_delegating_t *impl_from_delegating( IRpcStubBuffer *iface ) +{ + return (cstdstubbuffer_delegating_t*)((char *)iface - FIELD_OFFSET(cstdstubbuffer_delegating_t, stub_buffer)); +} + +HRESULT WINAPI CStdStubBuffer_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub) +{ + CStdStubBuffer *This; + IUnknown *pvServer; + HRESULT r; + TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); + TRACE("iid=%s\n", debugstr_guid(vtbl->header.piid)); + TRACE("vtbl=%p\n", &vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) { + ERR("IID mismatch during stub creation\n"); + return RPC_E_UNEXPECTED; + } + + r = IUnknown_QueryInterface(pUnkServer, riid, (void**)&pvServer); + if(FAILED(r)) + return r; + + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CStdStubBuffer)); + if (!This) { + IUnknown_Release(pvServer); + return E_OUTOFMEMORY; + } + + This->lpVtbl = &vtbl->Vtbl; + This->RefCount = 1; + This->pvServerObject = pvServer; + This->pPSFactory = pPSFactory; + *ppStub = (LPRPCSTUBBUFFER)This; + + IPSFactoryBuffer_AddRef(pPSFactory); + return S_OK; +} + +static CRITICAL_SECTION delegating_vtbl_section; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &delegating_vtbl_section, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": delegating_vtbl_section") } +}; +static CRITICAL_SECTION delegating_vtbl_section = { &critsect_debug, -1, 0, 0, 0, 0 }; + +typedef struct +{ + DWORD ref; + IUnknownVtbl vtbl; +} ref_counted_vtbl; + +static struct +{ + ref_counted_vtbl *table; + DWORD size; +} current_vtbl; + + +static HRESULT WINAPI delegating_QueryInterface(IUnknown *pUnk, REFIID iid, void **ppv) +{ + *ppv = (void *)pUnk; + return S_OK; +} + +static ULONG WINAPI delegating_AddRef(IUnknown *pUnk) +{ + return 1; +} + +static ULONG WINAPI delegating_Release(IUnknown *pUnk) +{ + return 1; +} + +#if defined(__i386__) + +/* The idea here is to replace the first param on the stack + ie. This (which will point to cstdstubbuffer_delegating_t) + with This->stub_buffer.pvServerObject and then jump to the + relevant offset in This->stub_buffer.pvServerObject's vtbl. +*/ +#include "pshpack1.h" +typedef struct { + DWORD mov1; /* mov 0x4(%esp), %eax 8b 44 24 04 */ + WORD mov2; /* mov 0x10(%eax), %eax 8b 40 */ + BYTE sixteen; /* 10 */ + DWORD mov3; /* mov %eax, 0x4(%esp) 89 44 24 04 */ + WORD mov4; /* mov (%eax), %eax 8b 00 */ + WORD mov5; /* mov offset(%eax), %eax 8b 80 */ + DWORD offset; /* xx xx xx xx */ + WORD jmp; /* jmp *%eax ff e0 */ + BYTE pad[3]; /* lea 0x0(%esi), %esi 8d 76 00 */ +} vtbl_method_t; +#include "poppack.h" + +static void fill_table(IUnknownVtbl *vtbl, DWORD num) +{ + vtbl_method_t *method; + void **entry; + DWORD i; + + vtbl->QueryInterface = delegating_QueryInterface; + vtbl->AddRef = delegating_AddRef; + vtbl->Release = delegating_Release; + + method = (vtbl_method_t*)((void **)vtbl + num); + entry = (void**)(vtbl + 1); + + for(i = 3; i < num; i++) + { + *entry = method; + method->mov1 = 0x0424448b; + method->mov2 = 0x408b; + method->sixteen = 0x10; + method->mov3 = 0x04244489; + method->mov4 = 0x008b; + method->mov5 = 0x808b; + method->offset = i << 2; + method->jmp = 0xe0ff; + method->pad[0] = 0x8d; + method->pad[1] = 0x76; + method->pad[2] = 0x00; + + method++; + entry++; + } +} + +#else /* __i386__ */ + +typedef struct {int dummy;} vtbl_method_t; +static void fill_table(IUnknownVtbl *vtbl, DWORD num) +{ + ERR("delegated stubs are not supported on this architecture\n"); +} + +#endif /* __i386__ */ + +void create_delegating_vtbl(DWORD num_methods) +{ + TRACE("%d\n", num_methods); + if(num_methods <= 3) + { + ERR("should have more than %d methods\n", num_methods); + return; + } + + EnterCriticalSection(&delegating_vtbl_section); + if(num_methods > current_vtbl.size) + { + DWORD size; + if(current_vtbl.table && current_vtbl.table->ref == 0) + { + TRACE("freeing old table\n"); + HeapFree(GetProcessHeap(), 0, current_vtbl.table); + } + size = sizeof(DWORD) + num_methods * sizeof(void*) + (num_methods - 3) * sizeof(vtbl_method_t); + current_vtbl.table = HeapAlloc(GetProcessHeap(), 0, size); + fill_table(¤t_vtbl.table->vtbl, num_methods); + current_vtbl.table->ref = 0; + current_vtbl.size = num_methods; + } + LeaveCriticalSection(&delegating_vtbl_section); +} + +static IUnknownVtbl *get_delegating_vtbl(void) +{ + IUnknownVtbl *ret; + + EnterCriticalSection(&delegating_vtbl_section); + current_vtbl.table->ref++; + ret = ¤t_vtbl.table->vtbl; + LeaveCriticalSection(&delegating_vtbl_section); + return ret; +} + +static void release_delegating_vtbl(IUnknownVtbl *vtbl) +{ + ref_counted_vtbl *table = (ref_counted_vtbl*)((DWORD *)vtbl - 1); + + EnterCriticalSection(&delegating_vtbl_section); + table->ref--; + TRACE("ref now %d\n", table->ref); + if(table->ref == 0 && table != current_vtbl.table) + { + TRACE("... and we're not current so free'ing\n"); + HeapFree(GetProcessHeap(), 0, table); + } + LeaveCriticalSection(&delegating_vtbl_section); +} + +HRESULT WINAPI CStdStubBuffer_Delegating_Construct(REFIID riid, + LPUNKNOWN pUnkServer, + PCInterfaceName name, + CInterfaceStubVtbl *vtbl, + REFIID delegating_iid, + LPPSFACTORYBUFFER pPSFactory, + LPRPCSTUBBUFFER *ppStub) +{ + cstdstubbuffer_delegating_t *This; + IUnknown *pvServer; + HRESULT r; + + TRACE("(%p,%p,%p,%p) %s\n", pUnkServer, vtbl, pPSFactory, ppStub, name); + TRACE("iid=%s delegating to %s\n", debugstr_guid(vtbl->header.piid), debugstr_guid(delegating_iid)); + TRACE("vtbl=%p\n", &vtbl->Vtbl); + + if (!IsEqualGUID(vtbl->header.piid, riid)) + { + ERR("IID mismatch during stub creation\n"); + return RPC_E_UNEXPECTED; + } + + r = IUnknown_QueryInterface(pUnkServer, riid, (void**)&pvServer); + if(FAILED(r)) return r; + + This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*This)); + if (!This) + { + IUnknown_Release(pvServer); + return E_OUTOFMEMORY; + } + + This->base_obj = get_delegating_vtbl(); + r = create_stub(delegating_iid, (IUnknown*)&This->base_obj, &This->base_stub); + if(FAILED(r)) + { + release_delegating_vtbl(This->base_obj); + HeapFree(GetProcessHeap(), 0, This); + IUnknown_Release(pvServer); + return r; + } + + This->stub_buffer.lpVtbl = &vtbl->Vtbl; + This->stub_buffer.RefCount = 1; + This->stub_buffer.pvServerObject = pvServer; + This->stub_buffer.pPSFactory = pPSFactory; + *ppStub = (LPRPCSTUBBUFFER)&This->stub_buffer; + + IPSFactoryBuffer_AddRef(pPSFactory); + return S_OK; +} + +HRESULT WINAPI CStdStubBuffer_QueryInterface(LPRPCSTUBBUFFER iface, + REFIID riid, + LPVOID *obj) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj); + + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_IRpcStubBuffer, riid)) + { + IUnknown_AddRef(iface); + *obj = iface; + return S_OK; + } + *obj = NULL; + return E_NOINTERFACE; +} + +ULONG WINAPI CStdStubBuffer_AddRef(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->AddRef()\n",This); + return InterlockedIncrement(&This->RefCount); +} + +ULONG WINAPI NdrCStdStubBuffer_Release(LPRPCSTUBBUFFER iface, + LPPSFACTORYBUFFER pPSF) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + ULONG refs; + + TRACE("(%p)->Release()\n",This); + + refs = InterlockedDecrement(&This->RefCount); + if (!refs) + { + /* test_Release shows that native doesn't call Disconnect here. + We'll leave it in for the time being. */ + IRpcStubBuffer_Disconnect(iface); + + IPSFactoryBuffer_Release(pPSF); + HeapFree(GetProcessHeap(),0,This); + } + return refs; +} + +ULONG WINAPI NdrCStdStubBuffer2_Release(LPRPCSTUBBUFFER iface, + LPPSFACTORYBUFFER pPSF) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating( iface ); + ULONG refs; + + TRACE("(%p)->Release()\n", This); + + refs = InterlockedDecrement(&This->stub_buffer.RefCount); + if (!refs) + { + /* Just like NdrCStdStubBuffer_Release, we shouldn't call + Disconnect here */ + IRpcStubBuffer_Disconnect((IRpcStubBuffer *)&This->stub_buffer); + + IRpcStubBuffer_Release(This->base_stub); + release_delegating_vtbl(This->base_obj); + + IPSFactoryBuffer_Release(pPSF); + HeapFree(GetProcessHeap(), 0, This); + } + + return refs; +} + +HRESULT WINAPI CStdStubBuffer_Connect(LPRPCSTUBBUFFER iface, + LPUNKNOWN lpUnkServer) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + HRESULT r; + IUnknown *new = NULL; + + TRACE("(%p)->Connect(%p)\n",This,lpUnkServer); + + r = IUnknown_QueryInterface(lpUnkServer, STUB_HEADER(This).piid, (void**)&new); + new = InterlockedExchangePointer((void**)&This->pvServerObject, new); + if(new) + IUnknown_Release(new); + return r; +} + +void WINAPI CStdStubBuffer_Disconnect(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + IUnknown *old; + TRACE("(%p)->Disconnect()\n",This); + + old = InterlockedExchangePointer((void**)&This->pvServerObject, NULL); + + if(old) + IUnknown_Release(old); +} + +HRESULT WINAPI CStdStubBuffer_Invoke(LPRPCSTUBBUFFER iface, + PRPCOLEMESSAGE pMsg, + LPRPCCHANNELBUFFER pChannel) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + DWORD dwPhase = STUB_UNMARSHAL; + HRESULT hr = S_OK; + + TRACE("(%p)->Invoke(%p,%p)\n",This,pMsg,pChannel); + + __TRY + { + if (STUB_HEADER(This).pDispatchTable) + STUB_HEADER(This).pDispatchTable[pMsg->iMethod](iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); + else /* pure interpreted */ + NdrStubCall2(iface, pChannel, (PRPC_MESSAGE)pMsg, &dwPhase); + } + __EXCEPT(stub_filter) + { + DWORD dwExceptionCode = GetExceptionCode(); + WARN("a stub call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode); + if (FAILED(dwExceptionCode)) + hr = dwExceptionCode; + else + hr = HRESULT_FROM_WIN32(dwExceptionCode); + } + __ENDTRY + + return hr; +} + +LPRPCSTUBBUFFER WINAPI CStdStubBuffer_IsIIDSupported(LPRPCSTUBBUFFER iface, + REFIID riid) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->IsIIDSupported(%s)\n",This,debugstr_guid(riid)); + return IsEqualGUID(STUB_HEADER(This).piid, riid) ? iface : NULL; +} + +ULONG WINAPI CStdStubBuffer_CountRefs(LPRPCSTUBBUFFER iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->CountRefs()\n",This); + return This->RefCount; +} + +HRESULT WINAPI CStdStubBuffer_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, + LPVOID *ppv) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->DebugServerQueryInterface(%p)\n",This,ppv); + return S_OK; +} + +void WINAPI CStdStubBuffer_DebugServerRelease(LPRPCSTUBBUFFER iface, + LPVOID pv) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + TRACE("(%p)->DebugServerRelease(%p)\n",This,pv); +} + +const IRpcStubBufferVtbl CStdStubBuffer_Vtbl = +{ + CStdStubBuffer_QueryInterface, + CStdStubBuffer_AddRef, + NULL, + CStdStubBuffer_Connect, + CStdStubBuffer_Disconnect, + CStdStubBuffer_Invoke, + CStdStubBuffer_IsIIDSupported, + CStdStubBuffer_CountRefs, + CStdStubBuffer_DebugServerQueryInterface, + CStdStubBuffer_DebugServerRelease +}; + +static HRESULT WINAPI CStdStubBuffer_Delegating_Connect(LPRPCSTUBBUFFER iface, + LPUNKNOWN lpUnkServer) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + HRESULT r; + TRACE("(%p)->Connect(%p)\n", This, lpUnkServer); + + r = CStdStubBuffer_Connect(iface, lpUnkServer); + if(SUCCEEDED(r)) + r = IRpcStubBuffer_Connect(This->base_stub, (IUnknown*)&This->base_obj); + + return r; +} + +static void WINAPI CStdStubBuffer_Delegating_Disconnect(LPRPCSTUBBUFFER iface) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + TRACE("(%p)->Disconnect()\n", This); + + IRpcStubBuffer_Disconnect(This->base_stub); + CStdStubBuffer_Disconnect(iface); +} + +static ULONG WINAPI CStdStubBuffer_Delegating_CountRefs(LPRPCSTUBBUFFER iface) +{ + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + ULONG ret; + TRACE("(%p)->CountRefs()\n", This); + + ret = CStdStubBuffer_CountRefs(iface); + ret += IRpcStubBuffer_CountRefs(This->base_stub); + + return ret; +} + +const IRpcStubBufferVtbl CStdStubBuffer_Delegating_Vtbl = +{ + CStdStubBuffer_QueryInterface, + CStdStubBuffer_AddRef, + NULL, + CStdStubBuffer_Delegating_Connect, + CStdStubBuffer_Delegating_Disconnect, + CStdStubBuffer_Invoke, + CStdStubBuffer_IsIIDSupported, + CStdStubBuffer_Delegating_CountRefs, + CStdStubBuffer_DebugServerQueryInterface, + CStdStubBuffer_DebugServerRelease +}; + +const MIDL_SERVER_INFO *CStdStubBuffer_GetServerInfo(IRpcStubBuffer *iface) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + return STUB_HEADER(This).pServerInfo; +} + +/************************************************************************ + * NdrStubForwardingFunction [RPCRT4.@] + */ +void __RPC_STUB NdrStubForwardingFunction( IRpcStubBuffer *iface, IRpcChannelBuffer *pChannel, + PRPC_MESSAGE pMsg, DWORD *pdwStubPhase ) +{ + /* Note pMsg is passed intact since RPCOLEMESSAGE is basically a RPC_MESSAGE. */ + + cstdstubbuffer_delegating_t *This = impl_from_delegating(iface); + HRESULT r = IRpcStubBuffer_Invoke(This->base_stub, (RPCOLEMESSAGE*)pMsg, pChannel); + if(FAILED(r)) RpcRaiseException(r); + return; +} + +/*********************************************************************** + * NdrStubInitialize [RPCRT4.@] + */ +void WINAPI NdrStubInitialize(PRPC_MESSAGE pRpcMsg, + PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDescriptor, + LPRPCCHANNELBUFFER pRpcChannelBuffer) +{ + TRACE("(%p,%p,%p,%p)\n", pRpcMsg, pStubMsg, pStubDescriptor, pRpcChannelBuffer); + NdrServerInitializeNew(pRpcMsg, pStubMsg, pStubDescriptor); + pStubMsg->pRpcChannelBuffer = pRpcChannelBuffer; +} + +/*********************************************************************** + * NdrStubGetBuffer [RPCRT4.@] + */ +void WINAPI NdrStubGetBuffer(LPRPCSTUBBUFFER iface, + LPRPCCHANNELBUFFER pRpcChannelBuffer, + PMIDL_STUB_MESSAGE pStubMsg) +{ + CStdStubBuffer *This = (CStdStubBuffer *)iface; + HRESULT hr; + + TRACE("(%p, %p, %p)\n", This, pRpcChannelBuffer, pStubMsg); + + pStubMsg->RpcMsg->BufferLength = pStubMsg->BufferLength; + hr = IRpcChannelBuffer_GetBuffer(pRpcChannelBuffer, + (RPCOLEMESSAGE *)pStubMsg->RpcMsg, STUB_HEADER(This).piid); + if (FAILED(hr)) + { + RpcRaiseException(hr); + return; + } + + pStubMsg->BufferStart = pStubMsg->RpcMsg->Buffer; + pStubMsg->BufferEnd = pStubMsg->BufferStart + pStubMsg->BufferLength; + pStubMsg->Buffer = pStubMsg->BufferStart; +} diff --git a/reactos/dll/win32/rpcrt4_new/epm_towers.h b/reactos/dll/win32/rpcrt4_new/epm_towers.h new file mode 100644 index 00000000000..7570cc2e846 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/epm_towers.h @@ -0,0 +1,88 @@ +/* + * Endpoint Mapper Tower Definitions + * + * Copyright 2006 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 + * + */ + +#define EPM_PROTOCOL_DNET_NSP 0x04 +#define EPM_PROTOCOL_OSI_TP4 0x05 +#define EPM_PROTOCOL_OSI_CLNS 0x06 +#define EPM_PROTOCOL_TCP 0x07 +#define EPM_PROTOCOL_UDP 0x08 +#define EPM_PROTOCOL_IP 0x09 +#define EPM_PROTOCOL_NCADG 0x0a /* Connectionless RPC */ +#define EPM_PROTOCOL_NCACN 0x0b +#define EPM_PROTOCOL_NCALRPC 0x0c /* Local RPC */ +#define EPM_PROTOCOL_UUID 0x0d +#define EPM_PROTOCOL_IPX 0x0e +#define EPM_PROTOCOL_SMB 0x0f +#define EPM_PROTOCOL_PIPE 0x10 +#define EPM_PROTOCOL_NETBIOS 0x11 +#define EPM_PROTOCOL_NETBEUI 0x12 +#define EPM_PROTOCOL_SPX 0x13 +#define EPM_PROTOCOL_NB_IPX 0x14 /* NetBIOS over IPX */ +#define EPM_PROTOCOL_DSP 0x16 /* AppleTalk Data Stream Protocol */ +#define EPM_PROTOCOL_DDP 0x17 /* AppleTalk Data Datagram Protocol */ +#define EPM_PROTOCOL_APPLETALK 0x18 /* AppleTalk */ +#define EPM_PROTOCOL_VINES_SPP 0x1a +#define EPM_PROTOCOL_VINES_IPC 0x1b /* Inter Process Communication */ +#define EPM_PROTOCOL_STREETTALK 0x1c /* Vines Streettalk */ +#define EPM_PROTOCOL_HTTP 0x1f +#define EPM_PROTOCOL_UNIX_DS 0x20 /* Unix domain socket */ +#define EPM_PROTOCOL_NULL 0x21 + +#include + +typedef unsigned char u_int8; +typedef unsigned short u_int16; +typedef unsigned int u_int32; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + GUID uuid; + u_int16 major_version; + u_int16 count_rhs; + u_int16 minor_version; +} twr_uuid_floor_t; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + u_int16 count_rhs; + u_int16 port; +} twr_tcp_floor_t; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + u_int16 count_rhs; + u_int32 ipv4addr; +} twr_ipv4_floor_t; + +typedef struct +{ + u_int16 count_lhs; + u_int8 protid; + u_int16 count_rhs; +} twr_empty_floor_t; + +#include diff --git a/reactos/dll/win32/rpcrt4_new/ncastatus.h b/reactos/dll/win32/rpcrt4_new/ncastatus.h new file mode 100644 index 00000000000..0a9700268e2 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/ncastatus.h @@ -0,0 +1,66 @@ +/* + * NCA Status definitions + * + * Copyright 2007 Robert Shearman + * + * 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 + */ + +#define NCA_S_COMM_FAILURE 0x1C010001 +#define NCA_S_OP_RNG_ERROR 0x1C010002 +#define NCA_S_UNK_IF 0x1C010003 +#define NCA_S_WRONG_BOOT_TIME 0x1C010006 +#define NCA_S_YOU_CRASHED 0x1C010009 +#define NCA_S_PROTO_ERROR 0x1C01000B +#define NCA_S_OUT_ARGS_TOO_BIG 0x1C010013 +#define NCA_S_SERVER_TOO_BUSY 0x1C010014 +#define NCA_S_FAULT_STRING_TOO_LONG 0x1C010015 +#define NCA_S_UNSUPPORTED_TYPE 0x1C010017 + +#define NCA_S_FAULT_INT_DIV_BY_ZERO 0x1C000001 +#define NCA_S_FAULT_ADDR_ERROR 0x1C000002 +#define NCA_S_FAULT_FP_DIV_ZERO 0x1C000003 +#define NCA_S_FAULT_FP_UNDERFLOW 0x1C000004 +#define NCA_S_FAULT_FP_OVERFLOW 0x1C000005 +#define NCA_S_FAULT_INVALID_TAG 0x1C000006 +#define NCA_S_FAULT_INVALID_BOUND 0x1C000007 +#define NCA_S_RPC_VERSION_MISMATCH 0x1C000008 +#define NCA_S_UNSPEC_REJECT 0x1C000009 +#define NCA_S_BAD_ACTID 0x1C00000A +#define NCA_S_WHO_ARE_YOU_FAILED 0x1C00000B +#define NCA_S_MANAGER_NOT_ENTERED 0x1C00000C +#define NCA_S_FAULT_CANCEL 0x1C00000D +#define NCA_S_FAULT_ILL_INST 0x1C00000E +#define NCA_S_FAULT_FP_ERROR 0x1C00000F +#define NCA_S_FAULT_INT_OVERFLOW 0x1C000010 +#define NCA_S_FAULT_UNSPEC 0x1C000012 +#define NCA_S_FAULT_REMOTE_COMM_FAILURE 0x1C000013 +#define NCA_S_FAULT_PIPE_EMPTY 0x1C000014 +#define NCA_S_FAULT_PIPE_CLOSED 0x1C000015 +#define NCA_S_FAULT_PIPE_ORDER 0x1C000016 +#define NCA_S_FAULT_PIPE_DISCIPLINE 0x1C000017 +#define NCA_S_FAULT_PIPE_COMM_ERROR 0x1C000018 +#define NCA_S_FAULT_PIPE_MEMORY 0x1C000019 +#define NCA_S_FAULT_CONTEXT_MISMATCH 0x1C00001A +#define NCA_S_FAULT_REMOTE_NO_MEMORY 0x1C00001B +#define NCA_S_INVALID_PRES_CONTEXT_ID 0x1C00001C +#define NCA_S_UNSUPPORTED_AUTHN_LEVEL 0x1C00001D +#define NCA_S_INVALID_CHECKSUM 0x1C00001F +#define NCA_S_INVALID_CRC 0x1C000020 +#define NCA_S_FAULT_USER_DEFINED 0x1C000021 +#define NCA_S_FAULT_TX_OPEN_FAILED 0x1C000022 +#define NCA_S_FAULT_CODESET_CONV_ERROR 0x1C000023 +#define NCA_S_FAULT_OBJECT_NOT_FOUND 0x1C000024 +#define NCA_S_FAULT_NO_CLIENT_STUB 0x1C000025 diff --git a/reactos/dll/win32/rpcrt4_new/ndr_clientserver.c b/reactos/dll/win32/rpcrt4_new/ndr_clientserver.c new file mode 100644 index 00000000000..fe424a63cc0 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/ndr_clientserver.c @@ -0,0 +1,207 @@ +/* + * MIDL proxy/stub stuff + * + * Copyright 2002 Ove Kåven, TransGaming Technologies + * + * 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 + * + * TODO: + * - figure out whether we *really* got this right + * - check for errors and throw exceptions + */ + +#include +#include +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" + +#include "rpcproxy.h" + +#include "wine/debug.h" + +#include "ndr_misc.h" +#include "rpcndr.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +/************************************************************************ + * NdrClientInitializeNew [RPCRT4.@] + */ +void WINAPI NdrClientInitializeNew( PRPC_MESSAGE pRpcMessage, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc, unsigned int ProcNum ) +{ + TRACE("(pRpcMessage == ^%p, pStubMsg == ^%p, pStubDesc == ^%p, ProcNum == %d)\n", + pRpcMessage, pStubMsg, pStubDesc, ProcNum); + + assert( pRpcMessage && pStubMsg && pStubDesc ); + + pRpcMessage->Handle = NULL; + pRpcMessage->ProcNum = ProcNum; + pRpcMessage->RpcInterfaceInformation = pStubDesc->RpcInterfaceInformation; + pRpcMessage->RpcFlags = 0; + pRpcMessage->DataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; + + pStubMsg->RpcMsg = pRpcMessage; + pStubMsg->BufferStart = NULL; + pStubMsg->BufferEnd = NULL; + pStubMsg->BufferLength = 0; + pStubMsg->IsClient = TRUE; + pStubMsg->ReuseBuffer = FALSE; + pStubMsg->pAllocAllNodesContext = NULL; + pStubMsg->pPointerQueueState = NULL; + pStubMsg->IgnoreEmbeddedPointers = 0; + pStubMsg->PointerBufferMark = NULL; + pStubMsg->fBufferValid = 0; + pStubMsg->uFlags = 0; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->StackTop = NULL; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->FullPtrRefId = 0; + pStubMsg->PointerLength = 0; + pStubMsg->fInDontFree = 0; + pStubMsg->fDontCallFreeInst = 0; + pStubMsg->fInOnlyParam = 0; + pStubMsg->fHasReturn = 0; + pStubMsg->fHasExtensions = 0; + pStubMsg->fHasNewCorrDesc = 0; + pStubMsg->fUnused = 0; + pStubMsg->dwDestContext = MSHCTX_DIFFERENTMACHINE; + pStubMsg->pvDestContext = NULL; + pStubMsg->pRpcChannelBuffer = NULL; + pStubMsg->pArrayInfo = NULL; + pStubMsg->dwStubPhase = 0; + /* FIXME: LowStackMark */ + pStubMsg->pAsyncMsg = NULL; + pStubMsg->pCorrInfo = NULL; + pStubMsg->pCorrMemory = NULL; + pStubMsg->pMemoryList = NULL; +} + +/*********************************************************************** + * NdrServerInitializeNew [RPCRT4.@] + */ +unsigned char* WINAPI NdrServerInitializeNew( PRPC_MESSAGE pRpcMsg, PMIDL_STUB_MESSAGE pStubMsg, + PMIDL_STUB_DESC pStubDesc ) +{ + TRACE("(pRpcMsg == ^%p, pStubMsg == ^%p, pStubDesc == ^%p)\n", pRpcMsg, pStubMsg, pStubDesc); + + assert( pRpcMsg && pStubMsg && pStubDesc ); + + /* not everyone allocates stack space for w2kReserved */ + memset(pStubMsg, 0, FIELD_OFFSET(MIDL_STUB_MESSAGE,pCSInfo)); + + pStubMsg->ReuseBuffer = TRUE; + pStubMsg->IsClient = FALSE; + pStubMsg->StubDesc = pStubDesc; + pStubMsg->pfnAllocate = pStubDesc->pfnAllocate; + pStubMsg->pfnFree = pStubDesc->pfnFree; + pStubMsg->RpcMsg = pRpcMsg; + pStubMsg->Buffer = pStubMsg->BufferStart = pRpcMsg->Buffer; + pStubMsg->BufferLength = pRpcMsg->BufferLength; + pStubMsg->BufferEnd = pStubMsg->Buffer + pStubMsg->BufferLength; + + /* FIXME: determine the proper return value */ + return NULL; +} + +/*********************************************************************** + * NdrGetBuffer [RPCRT4.@] + */ +unsigned char *WINAPI NdrGetBuffer(PMIDL_STUB_MESSAGE stubmsg, ULONG buflen, RPC_BINDING_HANDLE handle) +{ + TRACE("(stubmsg == ^%p, buflen == %u, handle == %p): wild guess.\n", stubmsg, buflen, handle); + + assert( stubmsg && stubmsg->RpcMsg ); + + /* I guess this is our chance to put the binding handle into the RPC_MESSAGE */ + stubmsg->RpcMsg->Handle = handle; + + stubmsg->RpcMsg->BufferLength = buflen; + if (I_RpcGetBuffer(stubmsg->RpcMsg) != S_OK) + return NULL; + + stubmsg->Buffer = stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; + stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; + stubmsg->BufferEnd = stubmsg->Buffer + stubmsg->BufferLength; + return (stubmsg->Buffer = (unsigned char *)stubmsg->RpcMsg->Buffer); +} +/*********************************************************************** + * NdrFreeBuffer [RPCRT4.@] + */ +void WINAPI NdrFreeBuffer(PMIDL_STUB_MESSAGE pStubMsg) +{ + TRACE("(pStubMsg == ^%p): wild guess.\n", pStubMsg); + I_RpcFreeBuffer(pStubMsg->RpcMsg); + pStubMsg->BufferLength = 0; + pStubMsg->Buffer = pStubMsg->BufferEnd = (unsigned char *)(pStubMsg->RpcMsg->Buffer = NULL); +} + +/************************************************************************ + * NdrSendReceive [RPCRT4.@] + */ +unsigned char *WINAPI NdrSendReceive( PMIDL_STUB_MESSAGE stubmsg, unsigned char *buffer ) +{ + RPC_STATUS status; + + TRACE("(stubmsg == ^%p, buffer == ^%p)\n", stubmsg, buffer); + + /* FIXME: how to handle errors? (raise exception?) */ + if (!stubmsg) { + ERR("NULL stub message. No action taken.\n"); + return NULL; + } + if (!stubmsg->RpcMsg) { + ERR("RPC Message not present in stub message. No action taken.\n"); + return NULL; + } + + stubmsg->RpcMsg->BufferLength = buffer - (unsigned char *)stubmsg->RpcMsg->Buffer; + status = I_RpcSendReceive(stubmsg->RpcMsg); + if (status != RPC_S_OK) + RpcRaiseException(status); + + stubmsg->BufferLength = stubmsg->RpcMsg->BufferLength; + stubmsg->BufferStart = stubmsg->RpcMsg->Buffer; + stubmsg->BufferEnd = stubmsg->BufferStart + stubmsg->BufferLength; + stubmsg->Buffer = stubmsg->BufferStart; + + /* FIXME: is this the right return value? */ + return NULL; +} + +/************************************************************************ + * NdrMapCommAndFaultStatus [RPCRT4.@] + */ +RPC_STATUS RPC_ENTRY NdrMapCommAndFaultStatus( PMIDL_STUB_MESSAGE pStubMsg, + ULONG *pCommStatus, + ULONG *pFaultStatus, + RPC_STATUS Status ) +{ + FIXME("(%p, %p, %p, %ld): stub\n", pStubMsg, pCommStatus, pFaultStatus, Status); + + *pCommStatus = 0; + *pFaultStatus = 0; + + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4_new/ndr_fullpointer.c b/reactos/dll/win32/rpcrt4_new/ndr_fullpointer.c new file mode 100644 index 00000000000..5640769783d --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/ndr_fullpointer.c @@ -0,0 +1,233 @@ +/* + * Full Pointer Translation Routines + * + * Copyright 2006 Robert Shearman + * + * 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 "windef.h" +#include "winbase.h" +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +PFULL_PTR_XLAT_TABLES WINAPI NdrFullPointerXlatInit(ULONG NumberOfPointers, + XLAT_SIDE XlatSide) +{ + ULONG NumberOfBuckets; + PFULL_PTR_XLAT_TABLES pXlatTables = HeapAlloc(GetProcessHeap(), 0, sizeof(*pXlatTables)); + + TRACE("(%d, %d)\n", NumberOfPointers, XlatSide); + + if (!NumberOfPointers) NumberOfPointers = 512; + NumberOfBuckets = ((NumberOfPointers + 3) & ~3) - 1; + + pXlatTables->RefIdToPointer.XlatTable = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(void *) * NumberOfPointers); + pXlatTables->RefIdToPointer.StateTable = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(unsigned char) * NumberOfPointers); + pXlatTables->RefIdToPointer.NumberOfEntries = NumberOfPointers; + + TRACE("NumberOfBuckets = %d\n", NumberOfBuckets); + pXlatTables->PointerToRefId.XlatTable = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(PFULL_PTR_TO_REFID_ELEMENT) * NumberOfBuckets); + pXlatTables->PointerToRefId.NumberOfBuckets = NumberOfBuckets; + pXlatTables->PointerToRefId.HashMask = NumberOfBuckets - 1; + + pXlatTables->NextRefId = 1; + pXlatTables->XlatSide = XlatSide; + + return pXlatTables; +} + +void WINAPI NdrFullPointerXlatFree(PFULL_PTR_XLAT_TABLES pXlatTables) +{ + TRACE("(%p)\n", pXlatTables); + + HeapFree(GetProcessHeap(), 0, pXlatTables->RefIdToPointer.XlatTable); + HeapFree(GetProcessHeap(), 0, pXlatTables->RefIdToPointer.StateTable); + HeapFree(GetProcessHeap(), 0, pXlatTables->PointerToRefId.XlatTable); + + HeapFree(GetProcessHeap(), 0, pXlatTables); +} + +static void expand_pointer_table_if_necessary(PFULL_PTR_XLAT_TABLES pXlatTables, ULONG RefId) +{ + if (RefId >= pXlatTables->RefIdToPointer.NumberOfEntries) + { + pXlatTables->RefIdToPointer.NumberOfEntries = RefId * 2; + pXlatTables->RefIdToPointer.XlatTable = + HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pXlatTables->RefIdToPointer.XlatTable, + sizeof(void *) * pXlatTables->RefIdToPointer.NumberOfEntries); + pXlatTables->RefIdToPointer.StateTable = + HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pXlatTables->RefIdToPointer.StateTable, + sizeof(unsigned char) * pXlatTables->RefIdToPointer.NumberOfEntries); + + if (!pXlatTables->RefIdToPointer.XlatTable || !pXlatTables->RefIdToPointer.StateTable) + pXlatTables->RefIdToPointer.NumberOfEntries = 0; + } +} + +int WINAPI NdrFullPointerQueryPointer(PFULL_PTR_XLAT_TABLES pXlatTables, + void *pPointer, unsigned char QueryType, + ULONG *pRefId ) +{ + ULONG Hash = 0; + int i; + PFULL_PTR_TO_REFID_ELEMENT XlatTableEntry; + + TRACE("(%p, %p, %d, %p)\n", pXlatTables, pPointer, QueryType, pRefId); + + if (!pPointer) + { + *pRefId = 0; + return 1; + } + + /* simple hashing algorithm, don't know whether it matches native */ + for (i = 0; i < sizeof(pPointer); i++) + Hash = (Hash * 3) ^ ((unsigned char *)&pPointer)[i]; + + XlatTableEntry = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + for (; XlatTableEntry; XlatTableEntry = XlatTableEntry->Next) + if (pPointer == XlatTableEntry->Pointer) + { + *pRefId = XlatTableEntry->RefId; + if (XlatTableEntry->State & QueryType) + return 1; + XlatTableEntry->State |= QueryType; + return 0; + } + + XlatTableEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(*XlatTableEntry)); + XlatTableEntry->Next = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + XlatTableEntry->Pointer = pPointer; + XlatTableEntry->RefId = *pRefId = pXlatTables->NextRefId++; + XlatTableEntry->State = QueryType; + pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask] = XlatTableEntry; + + /* insert pointer into mapping table */ + expand_pointer_table_if_necessary(pXlatTables, XlatTableEntry->RefId); + if (pXlatTables->RefIdToPointer.NumberOfEntries > XlatTableEntry->RefId) + { + pXlatTables->RefIdToPointer.XlatTable[XlatTableEntry->RefId] = pPointer; + pXlatTables->RefIdToPointer.StateTable[XlatTableEntry->RefId] = QueryType; + } + + return 0; +} + +int WINAPI NdrFullPointerQueryRefId(PFULL_PTR_XLAT_TABLES pXlatTables, + ULONG RefId, unsigned char QueryType, + void **ppPointer) +{ + TRACE("(%p, 0x%x, %d, %p)\n", pXlatTables, RefId, QueryType, ppPointer); + + expand_pointer_table_if_necessary(pXlatTables, RefId); + + pXlatTables->NextRefId = max(RefId + 1, pXlatTables->NextRefId); + + if (pXlatTables->RefIdToPointer.NumberOfEntries > RefId) + { + *ppPointer = pXlatTables->RefIdToPointer.XlatTable[RefId]; + if (QueryType) + { + if (pXlatTables->RefIdToPointer.StateTable[RefId] & QueryType) + return 1; + pXlatTables->RefIdToPointer.StateTable[RefId] |= QueryType; + return 0; + } + else + return 0; + } + *ppPointer = NULL; + return 0; +} + +void WINAPI NdrFullPointerInsertRefId(PFULL_PTR_XLAT_TABLES pXlatTables, + ULONG RefId, void *pPointer) +{ + ULONG Hash = 0; + int i; + PFULL_PTR_TO_REFID_ELEMENT XlatTableEntry; + + TRACE("(%p, 0x%x, %p)\n", pXlatTables, RefId, pPointer); + + /* simple hashing algorithm, don't know whether it matches native */ + for (i = 0; i < sizeof(pPointer); i++) + Hash = (Hash * 3) ^ ((unsigned char *)&pPointer)[i]; + + XlatTableEntry = HeapAlloc(GetProcessHeap(), 0, sizeof(*XlatTableEntry)); + XlatTableEntry->Next = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + XlatTableEntry->Pointer = pPointer; + XlatTableEntry->RefId = RefId; + XlatTableEntry->State = 0; + pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask] = XlatTableEntry; + + /* insert pointer into mapping table */ + expand_pointer_table_if_necessary(pXlatTables, RefId); + if (pXlatTables->RefIdToPointer.NumberOfEntries > RefId) + pXlatTables->RefIdToPointer.XlatTable[XlatTableEntry->RefId] = pPointer; +} + +int WINAPI NdrFullPointerFree(PFULL_PTR_XLAT_TABLES pXlatTables, void *Pointer) +{ + ULONG Hash = 0; + int i; + PFULL_PTR_TO_REFID_ELEMENT XlatTableEntry; + ULONG RefId = 0; + + TRACE("(%p, %p)\n", pXlatTables, Pointer); + + if (!Pointer) + return 1; + + /* simple hashing algorithm, don't know whether it matches native */ + for (i = 0; i < sizeof(Pointer); i++) + Hash = (Hash * 3) ^ ((unsigned char *)&Pointer)[i]; + + XlatTableEntry = pXlatTables->PointerToRefId.XlatTable[Hash & pXlatTables->PointerToRefId.HashMask]; + for (; XlatTableEntry; XlatTableEntry = XlatTableEntry->Next) + if (Pointer == XlatTableEntry->Pointer) + { + if (XlatTableEntry->State & 0x20) + return 0; + XlatTableEntry->State |= 0x20; + RefId = XlatTableEntry->RefId; + break; + } + + if (!XlatTableEntry) + return 0; + + if (pXlatTables->RefIdToPointer.NumberOfEntries > RefId) + { + pXlatTables->RefIdToPointer.StateTable[RefId] |= 0x20; + return 1; + } + + return 0; +} diff --git a/reactos/dll/win32/rpcrt4_new/ndr_marshall.c b/reactos/dll/win32/rpcrt4_new/ndr_marshall.c new file mode 100644 index 00000000000..d8395b80d44 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/ndr_marshall.c @@ -0,0 +1,5914 @@ +/* + * NDR data marshalling + * + * Copyright 2002 Greg Turner + * Copyright 2003-2006 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 + * + * TODO: + * - Non-conformant strings + * - String structs + * - Encapsulated unions + * - Byte count pointers + * - transmit_as/represent as + * - Multi-dimensional arrays + * - Conversion functions (NdrConvert) + * - Checks for integer addition overflow + * - Checks for out-of-memory conditions + */ + +#include +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "ndr_misc.h" +#include "rpcndr.h" + +#include "wine/unicode.h" +#include "wine/rpcfc.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +#if defined(__i386__) +# define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*((UINT32 *)(pchar)) = (uint32)) + +# define LITTLE_ENDIAN_UINT32_READ(pchar) \ + (*((UINT32 *)(pchar))) +#else + /* these would work for i386 too, but less efficient */ +# define LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*(pchar) = LOBYTE(LOWORD(uint32)), \ + *((pchar)+1) = HIBYTE(LOWORD(uint32)), \ + *((pchar)+2) = LOBYTE(HIWORD(uint32)), \ + *((pchar)+3) = HIBYTE(HIWORD(uint32)), \ + (uint32)) /* allow as r-value */ + +# define LITTLE_ENDIAN_UINT32_READ(pchar) \ + (MAKELONG( \ + MAKEWORD(*(pchar), *((pchar)+1)), \ + MAKEWORD(*((pchar)+2), *((pchar)+3)))) +#endif + +#define BIG_ENDIAN_UINT32_WRITE(pchar, uint32) \ + (*((pchar)+3) = LOBYTE(LOWORD(uint32)), \ + *((pchar)+2) = HIBYTE(LOWORD(uint32)), \ + *((pchar)+1) = LOBYTE(HIWORD(uint32)), \ + *(pchar) = HIBYTE(HIWORD(uint32)), \ + (uint32)) /* allow as r-value */ + +#define BIG_ENDIAN_UINT32_READ(pchar) \ + (MAKELONG( \ + MAKEWORD(*((pchar)+3), *((pchar)+2)), \ + MAKEWORD(*((pchar)+1), *(pchar)))) + +#ifdef NDR_LOCAL_IS_BIG_ENDIAN +# define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ + BIG_ENDIAN_UINT32_WRITE(pchar, uint32) +# define NDR_LOCAL_UINT32_READ(pchar) \ + BIG_ENDIAN_UINT32_READ(pchar) +#else +# define NDR_LOCAL_UINT32_WRITE(pchar, uint32) \ + LITTLE_ENDIAN_UINT32_WRITE(pchar, uint32) +# define NDR_LOCAL_UINT32_READ(pchar) \ + LITTLE_ENDIAN_UINT32_READ(pchar) +#endif + +/* _Align must be the desired alignment, + * e.g. ALIGN_LENGTH(len, 4) to align on a dword boundary. */ +#define ALIGNED_LENGTH(_Len, _Align) (((_Len)+(_Align)-1)&~((_Align)-1)) +#define ALIGNED_POINTER(_Ptr, _Align) ((LPVOID)ALIGNED_LENGTH((ULONG_PTR)(_Ptr), _Align)) +#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align) +#define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align) + +#define STD_OVERFLOW_CHECK(_Msg) do { \ + TRACE("buffer=%d/%d\n", _Msg->Buffer - (unsigned char *)_Msg->RpcMsg->Buffer, _Msg->BufferLength); \ + if (_Msg->Buffer > (unsigned char *)_Msg->RpcMsg->Buffer + _Msg->BufferLength) \ + ERR("buffer overflow %d bytes\n", _Msg->Buffer - ((unsigned char *)_Msg->RpcMsg->Buffer + _Msg->BufferLength)); \ + } while (0) + +#define NDR_TABLE_SIZE 128 +#define NDR_TABLE_MASK 127 + +static unsigned char *WINAPI NdrBaseTypeMarshall(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); +static unsigned char *WINAPI NdrBaseTypeUnmarshall(PMIDL_STUB_MESSAGE, unsigned char **, PFORMAT_STRING, unsigned char); +static void WINAPI NdrBaseTypeBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); +static void WINAPI NdrBaseTypeFree(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); +static ULONG WINAPI NdrBaseTypeMemorySize(PMIDL_STUB_MESSAGE, PFORMAT_STRING); + +static unsigned char *WINAPI NdrContextHandleMarshall(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); +static void WINAPI NdrContextHandleBufferSize(PMIDL_STUB_MESSAGE, unsigned char *, PFORMAT_STRING); +static unsigned char *WINAPI NdrContextHandleUnmarshall(PMIDL_STUB_MESSAGE, unsigned char **, PFORMAT_STRING, unsigned char); + +const NDR_MARSHALL NdrMarshaller[NDR_TABLE_SIZE] = { + 0, + NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, + NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, + NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, + NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, NdrBaseTypeMarshall, + /* 0x10 */ + NdrBaseTypeMarshall, + /* 0x11 */ + NdrPointerMarshall, NdrPointerMarshall, + NdrPointerMarshall, NdrPointerMarshall, + /* 0x15 */ + NdrSimpleStructMarshall, NdrSimpleStructMarshall, + NdrConformantStructMarshall, NdrConformantStructMarshall, + NdrConformantVaryingStructMarshall, + NdrComplexStructMarshall, + /* 0x1b */ + NdrConformantArrayMarshall, + NdrConformantVaryingArrayMarshall, + NdrFixedArrayMarshall, NdrFixedArrayMarshall, + NdrVaryingArrayMarshall, NdrVaryingArrayMarshall, + NdrComplexArrayMarshall, + /* 0x22 */ + NdrConformantStringMarshall, 0, 0, + NdrConformantStringMarshall, + NdrNonConformantStringMarshall, 0, 0, 0, + /* 0x2a */ + NdrEncapsulatedUnionMarshall, + NdrNonEncapsulatedUnionMarshall, + NdrByteCountPointerMarshall, + NdrXmitOrRepAsMarshall, NdrXmitOrRepAsMarshall, + /* 0x2f */ + NdrInterfacePointerMarshall, + /* 0x30 */ + NdrContextHandleMarshall, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalMarshall, + 0, 0, + /* 0xb7 */ + NdrRangeMarshall +}; +const NDR_UNMARSHALL NdrUnmarshaller[NDR_TABLE_SIZE] = { + 0, + NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, + NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, + NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, + NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, NdrBaseTypeUnmarshall, + /* 0x10 */ + NdrBaseTypeUnmarshall, + /* 0x11 */ + NdrPointerUnmarshall, NdrPointerUnmarshall, + NdrPointerUnmarshall, NdrPointerUnmarshall, + /* 0x15 */ + NdrSimpleStructUnmarshall, NdrSimpleStructUnmarshall, + NdrConformantStructUnmarshall, NdrConformantStructUnmarshall, + NdrConformantVaryingStructUnmarshall, + NdrComplexStructUnmarshall, + /* 0x1b */ + NdrConformantArrayUnmarshall, + NdrConformantVaryingArrayUnmarshall, + NdrFixedArrayUnmarshall, NdrFixedArrayUnmarshall, + NdrVaryingArrayUnmarshall, NdrVaryingArrayUnmarshall, + NdrComplexArrayUnmarshall, + /* 0x22 */ + NdrConformantStringUnmarshall, 0, 0, + NdrConformantStringUnmarshall, + NdrNonConformantStringUnmarshall, 0, 0, 0, + /* 0x2a */ + NdrEncapsulatedUnionUnmarshall, + NdrNonEncapsulatedUnionUnmarshall, + NdrByteCountPointerUnmarshall, + NdrXmitOrRepAsUnmarshall, NdrXmitOrRepAsUnmarshall, + /* 0x2f */ + NdrInterfacePointerUnmarshall, + /* 0x30 */ + NdrContextHandleUnmarshall, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalUnmarshall, + 0, 0, + /* 0xb7 */ + NdrRangeUnmarshall +}; +const NDR_BUFFERSIZE NdrBufferSizer[NDR_TABLE_SIZE] = { + 0, + NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, + NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, + NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, + NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, NdrBaseTypeBufferSize, + /* 0x10 */ + NdrBaseTypeBufferSize, + /* 0x11 */ + NdrPointerBufferSize, NdrPointerBufferSize, + NdrPointerBufferSize, NdrPointerBufferSize, + /* 0x15 */ + NdrSimpleStructBufferSize, NdrSimpleStructBufferSize, + NdrConformantStructBufferSize, NdrConformantStructBufferSize, + NdrConformantVaryingStructBufferSize, + NdrComplexStructBufferSize, + /* 0x1b */ + NdrConformantArrayBufferSize, + NdrConformantVaryingArrayBufferSize, + NdrFixedArrayBufferSize, NdrFixedArrayBufferSize, + NdrVaryingArrayBufferSize, NdrVaryingArrayBufferSize, + NdrComplexArrayBufferSize, + /* 0x22 */ + NdrConformantStringBufferSize, 0, 0, + NdrConformantStringBufferSize, + NdrNonConformantStringBufferSize, 0, 0, 0, + /* 0x2a */ + NdrEncapsulatedUnionBufferSize, + NdrNonEncapsulatedUnionBufferSize, + NdrByteCountPointerBufferSize, + NdrXmitOrRepAsBufferSize, NdrXmitOrRepAsBufferSize, + /* 0x2f */ + NdrInterfacePointerBufferSize, + /* 0x30 */ + NdrContextHandleBufferSize, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalBufferSize, + 0, 0, + /* 0xb7 */ + NdrRangeBufferSize +}; +const NDR_MEMORYSIZE NdrMemorySizer[NDR_TABLE_SIZE] = { + 0, + NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, + NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, + NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, + NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, NdrBaseTypeMemorySize, + /* 0x10 */ + NdrBaseTypeMemorySize, + /* 0x11 */ + NdrPointerMemorySize, NdrPointerMemorySize, + NdrPointerMemorySize, NdrPointerMemorySize, + /* 0x15 */ + NdrSimpleStructMemorySize, NdrSimpleStructMemorySize, + NdrConformantStructMemorySize, NdrConformantStructMemorySize, + NdrConformantVaryingStructMemorySize, + NdrComplexStructMemorySize, + /* 0x1b */ + NdrConformantArrayMemorySize, + NdrConformantVaryingArrayMemorySize, + NdrFixedArrayMemorySize, NdrFixedArrayMemorySize, + NdrVaryingArrayMemorySize, NdrVaryingArrayMemorySize, + NdrComplexArrayMemorySize, + /* 0x22 */ + NdrConformantStringMemorySize, 0, 0, + NdrConformantStringMemorySize, + NdrNonConformantStringMemorySize, 0, 0, 0, + /* 0x2a */ + NdrEncapsulatedUnionMemorySize, + NdrNonEncapsulatedUnionMemorySize, + NdrByteCountPointerMemorySize, + NdrXmitOrRepAsMemorySize, NdrXmitOrRepAsMemorySize, + /* 0x2f */ + NdrInterfacePointerMemorySize, + /* 0x30 */ + 0, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalMemorySize, + 0, 0, + /* 0xb7 */ + NdrRangeMemorySize +}; +const NDR_FREE NdrFreer[NDR_TABLE_SIZE] = { + 0, + NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, + NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, + NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, + NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, NdrBaseTypeFree, + /* 0x10 */ + NdrBaseTypeFree, + /* 0x11 */ + NdrPointerFree, NdrPointerFree, + NdrPointerFree, NdrPointerFree, + /* 0x15 */ + NdrSimpleStructFree, NdrSimpleStructFree, + NdrConformantStructFree, NdrConformantStructFree, + NdrConformantVaryingStructFree, + NdrComplexStructFree, + /* 0x1b */ + NdrConformantArrayFree, + NdrConformantVaryingArrayFree, + NdrFixedArrayFree, NdrFixedArrayFree, + NdrVaryingArrayFree, NdrVaryingArrayFree, + NdrComplexArrayFree, + /* 0x22 */ + 0, 0, 0, + 0, 0, 0, 0, 0, + /* 0x2a */ + NdrEncapsulatedUnionFree, + NdrNonEncapsulatedUnionFree, + 0, + NdrXmitOrRepAsFree, NdrXmitOrRepAsFree, + /* 0x2f */ + NdrInterfacePointerFree, + /* 0x30 */ + 0, + /* 0xb1 */ + 0, 0, 0, + NdrUserMarshalFree, + 0, 0, + /* 0xb7 */ + NdrRangeFree +}; + +void * WINAPI NdrAllocate(MIDL_STUB_MESSAGE *pStubMsg, size_t len) +{ + /* hmm, this is probably supposed to do more? */ + return pStubMsg->pfnAllocate(len); +} + +static void WINAPI NdrFree(MIDL_STUB_MESSAGE *pStubMsg, unsigned char *Pointer) +{ + pStubMsg->pfnFree(Pointer); +} + +static inline BOOL IsConformanceOrVariancePresent(PFORMAT_STRING pFormat) +{ + return (*(const ULONG *)pFormat != -1); +} + +static PFORMAT_STRING ReadConformance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) +{ + ALIGN_POINTER(pStubMsg->Buffer, 4); + pStubMsg->MaxCount = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + TRACE("unmarshalled conformance is %ld\n", pStubMsg->MaxCount); + if (pStubMsg->fHasNewCorrDesc) + return pFormat+6; + else + return pFormat+4; +} + +static inline PFORMAT_STRING ReadVariance(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat, ULONG MaxValue) +{ + if (pFormat && !IsConformanceOrVariancePresent(pFormat)) + { + pStubMsg->Offset = 0; + pStubMsg->ActualCount = pStubMsg->MaxCount; + goto done; + } + + ALIGN_POINTER(pStubMsg->Buffer, 4); + pStubMsg->Offset = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + TRACE("offset is %d\n", pStubMsg->Offset); + pStubMsg->ActualCount = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); + pStubMsg->Buffer += 4; + TRACE("variance is %d\n", pStubMsg->ActualCount); + + if ((pStubMsg->ActualCount > MaxValue) || + (pStubMsg->ActualCount + pStubMsg->Offset > MaxValue)) + { + ERR("invalid array bound(s): ActualCount = %d, Offset = %d, MaxValue = %d\n", + pStubMsg->ActualCount, pStubMsg->Offset, MaxValue); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + +done: + if (pStubMsg->fHasNewCorrDesc) + return pFormat+6; + else + return pFormat+4; +} + +/* writes the conformance value to the buffer */ +static inline void WriteConformance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_POINTER(pStubMsg->Buffer, 4); + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->MaxCount); + pStubMsg->Buffer += 4; +} + +/* writes the variance values to the buffer */ +static inline void WriteVariance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_POINTER(pStubMsg->Buffer, 4); + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->Offset); + pStubMsg->Buffer += 4; + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, pStubMsg->ActualCount); + pStubMsg->Buffer += 4; +} + +/* requests buffer space for the conformance value */ +static inline void SizeConformance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 4; +} + +/* requests buffer space for the variance values */ +static inline void SizeVariance(MIDL_STUB_MESSAGE *pStubMsg) +{ + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 8; +} + +PFORMAT_STRING ComputeConformanceOrVariance( + MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat, ULONG_PTR def, ULONG_PTR *pCount) +{ + BYTE dtype = pFormat[0] & 0xf; + short ofs = *(const short *)&pFormat[2]; + LPVOID ptr = NULL; + DWORD data = 0; + + if (!IsConformanceOrVariancePresent(pFormat)) { + /* null descriptor */ + *pCount = def; + goto finish_conf; + } + + switch (pFormat[0] & 0xf0) { + case RPC_FC_NORMAL_CONFORMANCE: + TRACE("normal conformance, ofs=%d\n", ofs); + ptr = pMemory; + break; + case RPC_FC_POINTER_CONFORMANCE: + TRACE("pointer conformance, ofs=%d\n", ofs); + ptr = pStubMsg->Memory; + break; + case RPC_FC_TOP_LEVEL_CONFORMANCE: + TRACE("toplevel conformance, ofs=%d\n", ofs); + if (pStubMsg->StackTop) { + ptr = pStubMsg->StackTop; + } + else { + /* -Os mode, *pCount is already set */ + goto finish_conf; + } + break; + case RPC_FC_CONSTANT_CONFORMANCE: + data = ofs | ((DWORD)pFormat[1] << 16); + TRACE("constant conformance, val=%d\n", data); + *pCount = data; + goto finish_conf; + case RPC_FC_TOP_LEVEL_MULTID_CONFORMANCE: + FIXME("toplevel multidimensional conformance, ofs=%d\n", ofs); + if (pStubMsg->StackTop) { + ptr = pStubMsg->StackTop; + } + else { + /* ? */ + goto done_conf_grab; + } + break; + default: + FIXME("unknown conformance type %x\n", pFormat[0] & 0xf0); + } + + switch (pFormat[1]) { + case RPC_FC_DEREFERENCE: + ptr = *(LPVOID*)((char *)ptr + ofs); + break; + case RPC_FC_CALLBACK: + { + unsigned char *old_stack_top = pStubMsg->StackTop; + pStubMsg->StackTop = ptr; + + /* ofs is index into StubDesc->apfnExprEval */ + TRACE("callback conformance into apfnExprEval[%d]\n", ofs); + pStubMsg->StubDesc->apfnExprEval[ofs](pStubMsg); + + pStubMsg->StackTop = old_stack_top; + + /* the callback function always stores the computed value in MaxCount */ + *pCount = pStubMsg->MaxCount; + goto finish_conf; + } + default: + ptr = (char *)ptr + ofs; + break; + } + + switch (dtype) { + case RPC_FC_LONG: + case RPC_FC_ULONG: + data = *(DWORD*)ptr; + break; + case RPC_FC_SHORT: + data = *(SHORT*)ptr; + break; + case RPC_FC_USHORT: + data = *(USHORT*)ptr; + break; + case RPC_FC_CHAR: + case RPC_FC_SMALL: + data = *(CHAR*)ptr; + break; + case RPC_FC_BYTE: + case RPC_FC_USMALL: + data = *(UCHAR*)ptr; + break; + default: + FIXME("unknown conformance data type %x\n", dtype); + goto done_conf_grab; + } + TRACE("dereferenced data type %x at %p, got %d\n", dtype, ptr, data); + +done_conf_grab: + switch (pFormat[1]) { + case RPC_FC_DEREFERENCE: /* already handled */ + case 0: /* no op */ + *pCount = data; + break; + case RPC_FC_ADD_1: + *pCount = data + 1; + break; + case RPC_FC_SUB_1: + *pCount = data - 1; + break; + case RPC_FC_MULT_2: + *pCount = data * 2; + break; + case RPC_FC_DIV_2: + *pCount = data / 2; + break; + default: + FIXME("unknown conformance op %d\n", pFormat[1]); + goto finish_conf; + } + +finish_conf: + TRACE("resulting conformance is %ld\n", *pCount); + if (pStubMsg->fHasNewCorrDesc) + return pFormat+6; + else + return pFormat+4; +} + +/* multiply two numbers together, raising an RPC_S_INVALID_BOUND exception if + * the result overflows 32-bits */ +static inline ULONG safe_multiply(ULONG a, ULONG b) +{ + ULONGLONG ret = (ULONGLONG)a * b; + if (ret > 0xffffffff) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return 0; + } + return ret; +} + + +/* + * NdrConformantString: + * + * What MS calls a ConformantString is, in DCE terminology, + * a Varying-Conformant String. + * [ + * maxlen: DWORD (max # of CHARTYPE characters, inclusive of '\0') + * offset: DWORD (actual string data begins at (offset) CHARTYPE's + * into unmarshalled string) + * length: DWORD (# of CHARTYPE characters, inclusive of '\0') + * [ + * data: CHARTYPE[maxlen] + * ] + * ], where CHARTYPE is the appropriate character type (specified externally) + * + */ + +/*********************************************************************** + * NdrConformantStringMarshall [RPCRT4.@] + */ +unsigned char *WINAPI NdrConformantStringMarshall(MIDL_STUB_MESSAGE *pStubMsg, + unsigned char *pszMessage, PFORMAT_STRING pFormat) +{ + ULONG esize, size; + + TRACE("(pStubMsg == ^%p, pszMessage == ^%p, pFormat == ^%p)\n", pStubMsg, pszMessage, pFormat); + + if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a((char*)pszMessage)); + pStubMsg->ActualCount = strlen((char*)pszMessage)+1; + esize = 1; + } + else if (*pFormat == RPC_FC_C_WSTRING) { + TRACE("string=%s\n", debugstr_w((LPWSTR)pszMessage)); + pStubMsg->ActualCount = strlenW((LPWSTR)pszMessage)+1; + esize = 2; + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception. */ + return NULL; + } + + if (pFormat[1] == RPC_FC_STRING_SIZED) + pFormat = ComputeConformance(pStubMsg, pszMessage, pFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + pStubMsg->Offset = 0; + WriteConformance(pStubMsg); + WriteVariance(pStubMsg); + + size = safe_multiply(esize, pStubMsg->ActualCount); + memcpy(pStubMsg->Buffer, pszMessage, size); /* the string itself */ + pStubMsg->Buffer += size; + + STD_OVERFLOW_CHECK(pStubMsg); + + /* success */ + return NULL; /* is this always right? */ +} + +/*********************************************************************** + * NdrConformantStringBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, PFORMAT_STRING pFormat) +{ + ULONG esize; + + TRACE("(pStubMsg == ^%p, pMemory == ^%p, pFormat == ^%p)\n", pStubMsg, pMemory, pFormat); + + SizeConformance(pStubMsg); + SizeVariance(pStubMsg); + + if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a((char*)pMemory)); + pStubMsg->ActualCount = strlen((char*)pMemory)+1; + esize = 1; + } + else if (*pFormat == RPC_FC_C_WSTRING) { + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory)); + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory)+1; + esize = 2; + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + return; + } + + if (pFormat[1] == RPC_FC_STRING_SIZED) + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + + pStubMsg->BufferLength += safe_multiply(esize, pStubMsg->ActualCount); +} + +/************************************************************************ + * NdrConformantStringMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrConformantStringMemorySize( PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat ) +{ + ULONG rslt = 0; + + FIXME("(pStubMsg == ^%p, pFormat == ^%p)\n", pStubMsg, pFormat); + + assert(pStubMsg && pFormat); + + if (*pFormat == RPC_FC_C_CSTRING) { + rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer); /* maxlen */ + } + else if (*pFormat == RPC_FC_C_WSTRING) { + rslt = NDR_LOCAL_UINT32_READ(pStubMsg->Buffer)*2; /* maxlen */ + } + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + } + + if (pFormat[1] != RPC_FC_PAD) { + FIXME("sized string format=%d\n", pFormat[1]); + } + + TRACE(" --> %u\n", rslt); + return rslt; +} + +/************************************************************************ + * NdrConformantStringUnmarshall [RPCRT4.@] + */ +unsigned char *WINAPI NdrConformantStringUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char** ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc ) +{ + ULONG bufsize, memsize, esize, i; + + TRACE("(pStubMsg == ^%p, *pMemory == ^%p, pFormat == ^%p, fMustAlloc == %u)\n", + pStubMsg, *ppMemory, pFormat, fMustAlloc); + + assert(pFormat && ppMemory && pStubMsg); + + ReadConformance(pStubMsg, NULL); + ReadVariance(pStubMsg, NULL, pStubMsg->MaxCount); + + if (*pFormat == RPC_FC_C_CSTRING) esize = 1; + else if (*pFormat == RPC_FC_C_WSTRING) esize = 2; + else { + ERR("Unhandled string type: %#x\n", *pFormat); + /* FIXME: raise an exception */ + esize = 0; + } + + memsize = safe_multiply(esize, pStubMsg->MaxCount); + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + /* strings must always have null terminating bytes */ + if (bufsize < esize) + { + ERR("invalid string length of %d\n", pStubMsg->ActualCount); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + for (i = bufsize - esize; i < bufsize; i++) + if (pStubMsg->Buffer[i] != 0) + { + ERR("string not null-terminated at byte position %d, data is 0x%x\n", + i, pStubMsg->Buffer[i]); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, memsize); + + memcpy(*ppMemory, pStubMsg->Buffer, bufsize); + + pStubMsg->Buffer += bufsize; + + if (*pFormat == RPC_FC_C_CSTRING) { + TRACE("string=%s\n", debugstr_a((char*)*ppMemory)); + } + else if (*pFormat == RPC_FC_C_WSTRING) { + TRACE("string=%s\n", debugstr_w((LPWSTR)*ppMemory)); + } + + return NULL; /* FIXME: is this always right? */ +} + +/*********************************************************************** + * NdrNonConformantStringMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrNonConformantStringMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); + return NULL; +} + +/*********************************************************************** + * NdrNonConformantStringUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrNonConformantStringUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + FIXME("stub\n"); + return NULL; +} + +/*********************************************************************** + * NdrNonConformantStringBufferSize [RPCRT4.@] + */ +void WINAPI NdrNonConformantStringBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); +} + +/*********************************************************************** + * NdrNonConformantStringMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrNonConformantStringMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); + return 0; +} + +static inline void dump_pointer_attr(unsigned char attr) +{ + if (attr & RPC_FC_P_ALLOCALLNODES) + TRACE(" RPC_FC_P_ALLOCALLNODES"); + if (attr & RPC_FC_P_DONTFREE) + TRACE(" RPC_FC_P_DONTFREE"); + if (attr & RPC_FC_P_ONSTACK) + TRACE(" RPC_FC_P_ONSTACK"); + if (attr & RPC_FC_P_SIMPLEPOINTER) + TRACE(" RPC_FC_P_SIMPLEPOINTER"); + if (attr & RPC_FC_P_DEREF) + TRACE(" RPC_FC_P_DEREF"); + TRACE("\n"); +} + +/*********************************************************************** + * PointerMarshall [internal] + */ +static void PointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_MARSHALL m; + ULONG pointer_id; + int pointer_needs_marshaling; + + TRACE("(%p,%p,%p,%p)\n", pStubMsg, Buffer, Pointer, pFormat); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ +#if 0 /* this causes problems for InstallShield so is disabled - we need more tests */ + if (!Pointer) + RpcRaiseException(RPC_X_NULL_REF_POINTER); +#endif + pointer_needs_marshaling = 1; + break; + case RPC_FC_UP: /* unique pointer */ + case RPC_FC_OP: /* object pointer - same as unique here */ + if (Pointer) + pointer_needs_marshaling = 1; + else + pointer_needs_marshaling = 0; + pointer_id = (ULONG)Pointer; + TRACE("writing 0x%08x to buffer\n", pointer_id); + NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id); + break; + case RPC_FC_FP: + pointer_needs_marshaling = !NdrFullPointerQueryPointer( + pStubMsg->FullPtrXlatTables, Pointer, 1, &pointer_id); + TRACE("writing 0x%08x to buffer\n", pointer_id); + NDR_LOCAL_UINT32_WRITE(Buffer, pointer_id); + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + return; + } + + TRACE("calling marshaller for type 0x%x\n", (int)*desc); + + if (pointer_needs_marshaling) { + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + else FIXME("no marshaller for data type=%02x\n", *desc); + } + + STD_OVERFLOW_CHECK(pStubMsg); +} + +/*********************************************************************** + * PointerUnmarshall [internal] + */ +static void PointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + unsigned char **pPointer, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_UNMARSHALL m; + DWORD pointer_id = 0; + int pointer_needs_unmarshaling; + + TRACE("(%p,%p,%p,%p,%d)\n", pStubMsg, Buffer, pPointer, pFormat, fMustAlloc); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + pointer_needs_unmarshaling = 1; + break; + case RPC_FC_UP: /* unique pointer */ + pointer_id = NDR_LOCAL_UINT32_READ(Buffer); + TRACE("pointer_id is 0x%08x\n", pointer_id); + if (pointer_id) + pointer_needs_unmarshaling = 1; + else { + *pPointer = NULL; + pointer_needs_unmarshaling = 0; + } + break; + case RPC_FC_OP: /* object pointer - we must free data before overwriting it */ + pointer_id = NDR_LOCAL_UINT32_READ(Buffer); + TRACE("pointer_id is 0x%08x\n", pointer_id); + if (!fMustAlloc && *pPointer) + { + FIXME("free object pointer %p\n", *pPointer); + *pPointer = NULL; + } + if (pointer_id) + pointer_needs_unmarshaling = 1; + else + pointer_needs_unmarshaling = 0; + break; + case RPC_FC_FP: + pointer_id = NDR_LOCAL_UINT32_READ(Buffer); + TRACE("pointer_id is 0x%08x\n", pointer_id); + pointer_needs_unmarshaling = !NdrFullPointerQueryRefId( + pStubMsg->FullPtrXlatTables, pointer_id, 1, (void **)pPointer); + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + return; + } + + if (pointer_needs_unmarshaling) { + if (attr & RPC_FC_P_DEREF) { + if (!*pPointer || fMustAlloc) + *pPointer = NdrAllocate(pStubMsg, sizeof(void *)); + pPointer = *(unsigned char***)pPointer; + TRACE("deref => %p\n", pPointer); + } + m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pPointer, desc, fMustAlloc); + else FIXME("no unmarshaller for data type=%02x\n", *desc); + + if (type == RPC_FC_FP) + NdrFullPointerInsertRefId(pStubMsg->FullPtrXlatTables, pointer_id, + *pPointer); + } + + TRACE("pointer=%p\n", *pPointer); +} + +/*********************************************************************** + * PointerBufferSize [internal] + */ +static void PointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_BUFFERSIZE m; + int pointer_needs_sizing; + ULONG pointer_id; + + TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + case RPC_FC_OP: + case RPC_FC_UP: + /* NULL pointer has no further representation */ + if (!Pointer) + return; + break; + case RPC_FC_FP: + pointer_needs_sizing = !NdrFullPointerQueryPointer( + pStubMsg->FullPtrXlatTables, Pointer, 0, &pointer_id); + if (!pointer_needs_sizing) + return; + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + return; + } + + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + else FIXME("no buffersizer for data type=%02x\n", *desc); +} + +/*********************************************************************** + * PointerMemorySize [internal] + */ +static unsigned long PointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Buffer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_MEMORYSIZE m; + + FIXME("(%p,%p,%p): stub\n", pStubMsg, Buffer, pFormat); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + + switch (type) { + case RPC_FC_RP: /* ref pointer (always non-null) */ + break; + default: + FIXME("unhandled ptr type=%02x\n", type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + + if (attr & RPC_FC_P_DEREF) { + TRACE("deref\n"); + } + + m = NdrMemorySizer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, desc); + else FIXME("no memorysizer for data type=%02x\n", *desc); + + return 0; +} + +/*********************************************************************** + * PointerFree [internal] + */ +static void PointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *Pointer, + PFORMAT_STRING pFormat) +{ + unsigned type = pFormat[0], attr = pFormat[1]; + PFORMAT_STRING desc; + NDR_FREE m; + + TRACE("(%p,%p,%p)\n", pStubMsg, Pointer, pFormat); + TRACE("type=0x%x, attr=", type); dump_pointer_attr(attr); + if (attr & RPC_FC_P_DONTFREE) return; + pFormat += 2; + if (attr & RPC_FC_P_SIMPLEPOINTER) desc = pFormat; + else desc = pFormat + *(const SHORT*)pFormat; + + if (!Pointer) return; + + if (type == RPC_FC_FP) { + int pointer_needs_freeing = NdrFullPointerFree( + pStubMsg->FullPtrXlatTables, Pointer); + if (!pointer_needs_freeing) + return; + } + + if (attr & RPC_FC_P_DEREF) { + Pointer = *(unsigned char**)Pointer; + TRACE("deref => %p\n", Pointer); + } + + m = NdrFreer[*desc & NDR_TABLE_MASK]; + if (m) m(pStubMsg, Pointer, desc); + + /* hmm... is this sensible? + * perhaps we should check if the memory comes from NdrAllocate, + * and deallocate only if so - checking if the pointer is between + * BufferStart and BufferEnd is probably no good since the buffer + * may be reallocated when the server wants to marshal the reply */ + switch (*desc) { + case RPC_FC_BOGUS_STRUCT: + case RPC_FC_BOGUS_ARRAY: + case RPC_FC_USER_MARSHAL: + case RPC_FC_CARRAY: + case RPC_FC_CVARRAY: + break; + default: + FIXME("unhandled data type=%02x\n", *desc); + break; + case RPC_FC_C_CSTRING: + case RPC_FC_C_WSTRING: + if (pStubMsg->ReuseBuffer) goto notfree; + break; + case RPC_FC_IP: + goto notfree; + } + + if (attr & RPC_FC_P_ONSTACK) { + TRACE("not freeing stack ptr %p\n", Pointer); + return; + } + TRACE("freeing %p\n", Pointer); + NdrFree(pStubMsg, Pointer); + return; +notfree: + TRACE("not freeing %p\n", Pointer); +} + +/*********************************************************************** + * EmbeddedPointerMarshall + */ +static unsigned char * EmbeddedPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char *Mark = pStubMsg->BufferMark; + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + unsigned i; + unsigned char *saved_buffer = NULL; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (*pFormat != RPC_FC_PP) return NULL; + pFormat += 2; + + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + for (i = 0; i < rep; i++) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + ofs + (i * stride); + unsigned char *bufbase = Mark + ofs + (i * stride); + unsigned u; + + for (u=0; uMemory; + + pStubMsg->Memory = pMemory; + PointerMarshall(pStubMsg, bufptr, *(unsigned char**)memptr, info+4); + pStubMsg->Memory = saved_memory; + } + } + pFormat += 8 * count; + } + + if (saved_buffer) + { + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * EmbeddedPointerUnmarshall + */ +static unsigned char * EmbeddedPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned char *Mark = pStubMsg->BufferMark; + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + unsigned i; + unsigned char *saved_buffer = NULL; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (*pFormat != RPC_FC_PP) return NULL; + pFormat += 2; + + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + + while (pFormat[0] != RPC_FC_END) { + TRACE("pFormat[0] = 0x%x\n", pFormat[0]); + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + for (i = 0; i < rep; i++) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = *ppMemory + ofs + (i * stride); + unsigned char *bufbase = Mark + ofs + (i * stride); + unsigned u; + + for (u=0; uPointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + + return NULL; +} + +/*********************************************************************** + * EmbeddedPointerBufferSize + */ +static void EmbeddedPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned long Offset = pStubMsg->Offset; + unsigned ofs, rep, count, stride, xofs; + unsigned i; + ULONG saved_buffer_length = 0; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (pStubMsg->IgnoreEmbeddedPointers) return; + + if (*pFormat != RPC_FC_PP) return; + pFormat += 2; + + if (pStubMsg->PointerLength) + { + saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + for (i = 0; i < rep; i++) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + ofs + (i * stride); + unsigned u; + + for (u=0; uMemory; + + pStubMsg->Memory = pMemory; + PointerBufferSize(pStubMsg, *(unsigned char**)memptr, info+4); + pStubMsg->Memory = saved_memory; + } + } + pFormat += 8 * count; + } + + if (saved_buffer_length) + { + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; + } +} + +/*********************************************************************** + * EmbeddedPointerMemorySize [internal] + */ +static unsigned long EmbeddedPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned long Offset = pStubMsg->Offset; + unsigned char *Mark = pStubMsg->BufferMark; + unsigned ofs, rep, count, stride, xofs; + unsigned i; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + if (pStubMsg->IgnoreEmbeddedPointers) return 0; + + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + + if (*pFormat != RPC_FC_PP) return 0; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + /* ofs doesn't seem to matter in this context */ + for (i = 0; i < rep; i++) { + PFORMAT_STRING info = pFormat; + unsigned char *bufbase = Mark + ofs + (i * stride); + unsigned u; + for (u=0; uOffset; + unsigned ofs, rep, count, stride, xofs; + unsigned i; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (*pFormat != RPC_FC_PP) return; + pFormat += 2; + + while (pFormat[0] != RPC_FC_END) { + switch (pFormat[0]) { + default: + FIXME("unknown repeat type %d\n", pFormat[0]); + case RPC_FC_NO_REPEAT: + rep = 1; + stride = 0; + ofs = 0; + count = 1; + xofs = 0; + pFormat += 2; + break; + case RPC_FC_FIXED_REPEAT: + rep = *(const WORD*)&pFormat[2]; + stride = *(const WORD*)&pFormat[4]; + ofs = *(const WORD*)&pFormat[6]; + count = *(const WORD*)&pFormat[8]; + xofs = 0; + pFormat += 10; + break; + case RPC_FC_VARIABLE_REPEAT: + rep = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? pStubMsg->ActualCount : pStubMsg->MaxCount; + stride = *(const WORD*)&pFormat[2]; + ofs = *(const WORD*)&pFormat[4]; + count = *(const WORD*)&pFormat[6]; + xofs = (pFormat[1] == RPC_FC_VARIABLE_OFFSET) ? Offset * stride : 0; + pFormat += 8; + break; + } + for (i = 0; i < rep; i++) { + PFORMAT_STRING info = pFormat; + unsigned char *membase = pMemory + (i * stride); + unsigned u; + + for (u=0; uMemory; + + pStubMsg->Memory = pMemory; + PointerFree(pStubMsg, *(unsigned char**)memptr, info+4); + pStubMsg->Memory = saved_memory; + } + } + pFormat += 8 * count; + } +} + +/*********************************************************************** + * NdrPointerMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char *Buffer; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + /* incremement the buffer here instead of in PointerMarshall, + * as that is used by embedded pointers which already handle the incrementing + * the buffer, and shouldn't write any additional pointer data to the wire */ + if (*pFormat != RPC_FC_RP) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + Buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; + } + else + Buffer = pStubMsg->Buffer; + + PointerMarshall(pStubMsg, Buffer, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrPointerUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned char *Buffer; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + /* incremement the buffer here instead of in PointerUnmarshall, + * as that is used by embedded pointers which already handle the incrementing + * the buffer, and shouldn't read any additional pointer data from the + * buffer */ + if (*pFormat != RPC_FC_RP) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + Buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; + } + else + Buffer = pStubMsg->Buffer; + + PointerUnmarshall(pStubMsg, Buffer, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrPointerBufferSize [RPCRT4.@] + */ +void WINAPI NdrPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + /* incremement the buffer length here instead of in PointerBufferSize, + * as that is used by embedded pointers which already handle the buffer + * length, and shouldn't write anything more to the wire */ + if (*pFormat != RPC_FC_RP) + { + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 4; + } + + PointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrPointerMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + /* unsigned size = *(LPWORD)(pFormat+2); */ + FIXME("(%p,%p): stub\n", pStubMsg, pFormat); + PointerMemorySize(pStubMsg, pStubMsg->Buffer, pFormat); + return 0; +} + +/*********************************************************************** + * NdrPointerFree [RPCRT4.@] + */ +void WINAPI NdrPointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + PointerFree(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrSimpleTypeMarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeMarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, + unsigned char FormatChar ) +{ + NdrBaseTypeMarshall(pStubMsg, pMemory, &FormatChar); +} + +/*********************************************************************** + * NdrSimpleTypeUnmarshall [RPCRT4.@] + */ +void WINAPI NdrSimpleTypeUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, unsigned char* pMemory, + unsigned char FormatChar ) +{ + NdrBaseTypeUnmarshall(pStubMsg, &pMemory, &FormatChar, 0); +} + +/*********************************************************************** + * NdrSimpleStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrSimpleStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + + memcpy(pStubMsg->Buffer, pMemory, size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat+4); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrSimpleStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrSimpleStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + + if (fMustAlloc) { + *ppMemory = NdrAllocate(pStubMsg, size); + memcpy(*ppMemory, pStubMsg->Buffer, size); + } else { + if (!pStubMsg->IsClient && !*ppMemory) + /* for servers, we just point straight into the RPC buffer */ + *ppMemory = pStubMsg->Buffer; + else + /* for clients, memory should be provided by caller */ + memcpy(*ppMemory, pStubMsg->Buffer, size); + } + + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat+4, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrSimpleStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrSimpleStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned size = *(const WORD*)(pFormat+2); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + ALIGN_LENGTH(pStubMsg->BufferLength, pFormat[1] + 1); + + pStubMsg->BufferLength += size; + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat+4); +} + +/*********************************************************************** + * NdrSimpleStructMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrSimpleStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned short size = *(const WORD *)(pFormat+2); + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + pStubMsg->MemorySize += size; + pStubMsg->Buffer += size; + + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerMemorySize(pStubMsg, pFormat+4); + return size; +} + +/*********************************************************************** + * NdrSimpleStructFree [RPCRT4.@] + */ +void WINAPI NdrSimpleStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_STRUCT) + EmbeddedPointerFree(pStubMsg, pMemory, pFormat+4); +} + + +static unsigned long EmbeddedComplexSize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + switch (*pFormat) { + case RPC_FC_STRUCT: + case RPC_FC_PSTRUCT: + case RPC_FC_CSTRUCT: + case RPC_FC_BOGUS_STRUCT: + case RPC_FC_SMFARRAY: + case RPC_FC_SMVARRAY: + return *(const WORD*)&pFormat[2]; + case RPC_FC_USER_MARSHAL: + return *(const WORD*)&pFormat[4]; + case RPC_FC_NON_ENCAPSULATED_UNION: + pFormat += 2; + if (pStubMsg->fHasNewCorrDesc) + pFormat += 6; + else + pFormat += 4; + + pFormat += *(const SHORT*)pFormat; + return *(const SHORT*)pFormat; + case RPC_FC_IP: + return sizeof(void *); + default: + FIXME("unhandled embedded type %02x\n", *pFormat); + } + return 0; +} + + +static unsigned long EmbeddedComplexMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + NDR_MEMORYSIZE m = NdrMemorySizer[*pFormat & NDR_TABLE_MASK]; + + if (!m) + { + FIXME("no memorysizer for data type=%02x\n", *pFormat); + return 0; + } + + return m(pStubMsg, pFormat); +} + + +static unsigned char * ComplexMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_MARSHALL m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + TRACE("byte=%d <= %p\n", *(WORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 1); + pStubMsg->Buffer += 1; + pMemory += 1; + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + TRACE("short=%d <= %p\n", *(WORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 2); + pStubMsg->Buffer += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + TRACE("long=%d <= %p\n", *(DWORD*)pMemory, pMemory); + memcpy(pStubMsg->Buffer, pMemory, 4); + pStubMsg->Buffer += 4; + pMemory += 4; + break; + case RPC_FC_HYPER: + TRACE("longlong=%s <= %p\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory), pMemory); + memcpy(pStubMsg->Buffer, pMemory, 8); + pStubMsg->Buffer += 8; + pMemory += 8; + break; + case RPC_FC_POINTER: + { + unsigned char *saved_buffer; + int pointer_buffer_mark_set = 0; + TRACE("pointer=%p <= %p\n", *(unsigned char**)pMemory, pMemory); + saved_buffer = pStubMsg->Buffer; + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + PointerMarshall(pStubMsg, saved_buffer, *(unsigned char**)pMemory, pPointer); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } + pPointer += 4; + pMemory += 4; + break; + } + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 4); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 8); + break; + case RPC_FC_STRUCTPAD1: + case RPC_FC_STRUCTPAD2: + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + TRACE("embedded complex (size=%ld) <= %p\n", size, pMemory); + m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, *(unsigned char **)pMemory, desc); + else + m(pStubMsg, pMemory, desc); + } + else FIXME("no marshaller for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format 0x%02x\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +static unsigned char * ComplexUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_UNMARSHALL m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + memcpy(pMemory, pStubMsg->Buffer, 1); + TRACE("byte=%d => %p\n", *(WORD*)pMemory, pMemory); + pStubMsg->Buffer += 1; + pMemory += 1; + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + memcpy(pMemory, pStubMsg->Buffer, 2); + TRACE("short=%d => %p\n", *(WORD*)pMemory, pMemory); + pStubMsg->Buffer += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + memcpy(pMemory, pStubMsg->Buffer, 4); + TRACE("long=%d => %p\n", *(DWORD*)pMemory, pMemory); + pStubMsg->Buffer += 4; + pMemory += 4; + break; + case RPC_FC_HYPER: + memcpy(pMemory, pStubMsg->Buffer, 8); + TRACE("longlong=%s => %p\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory), pMemory); + pStubMsg->Buffer += 8; + pMemory += 8; + break; + case RPC_FC_POINTER: + { + unsigned char *saved_buffer; + int pointer_buffer_mark_set = 0; + TRACE("pointer => %p\n", pMemory); + ALIGN_POINTER(pStubMsg->Buffer, 4); + saved_buffer = pStubMsg->Buffer; + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + + PointerUnmarshall(pStubMsg, saved_buffer, (unsigned char**)pMemory, pPointer, TRUE); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } + pPointer += 4; + pMemory += 4; + break; + } + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 4); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 8); + break; + case RPC_FC_STRUCTPAD1: + case RPC_FC_STRUCTPAD2: + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + TRACE("embedded complex (size=%ld) => %p\n", size, pMemory); + m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + memset(pMemory, 0, size); /* just in case */ + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, (unsigned char **)pMemory, desc, FALSE); + else + m(pStubMsg, &pMemory, desc, FALSE); + } + else FIXME("no unmarshaller for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format %d\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +static unsigned char * ComplexBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_BUFFERSIZE m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + pStubMsg->BufferLength += 1; + pMemory += 1; + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + pStubMsg->BufferLength += 2; + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + pStubMsg->BufferLength += 4; + pMemory += 4; + break; + case RPC_FC_HYPER: + pStubMsg->BufferLength += 8; + pMemory += 8; + break; + case RPC_FC_POINTER: + if (!pStubMsg->IgnoreEmbeddedPointers) + { + int saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + if(!pStubMsg->BufferLength) + ERR("BufferLength == 0??\n"); + PointerBufferSize(pStubMsg, *(unsigned char**)pMemory, pPointer); + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; + } + pStubMsg->BufferLength += 4; + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 4); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 8); + break; + case RPC_FC_STRUCTPAD1: + case RPC_FC_STRUCTPAD2: + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, *(unsigned char **)pMemory, desc); + else + m(pStubMsg, pMemory, desc); + } + else FIXME("no buffersizer for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format 0x%02x\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +static unsigned char * ComplexFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat, + PFORMAT_STRING pPointer) +{ + PFORMAT_STRING desc; + NDR_FREE m; + unsigned long size; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + pMemory += 1; + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + pMemory += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + pMemory += 4; + break; + case RPC_FC_HYPER: + pMemory += 8; + break; + case RPC_FC_POINTER: + NdrPointerFree(pStubMsg, *(unsigned char**)pMemory, pPointer); + pPointer += 4; + pMemory += 4; + break; + case RPC_FC_ALIGNM4: + ALIGN_POINTER(pMemory, 4); + break; + case RPC_FC_ALIGNM8: + ALIGN_POINTER(pMemory, 8); + break; + case RPC_FC_STRUCTPAD1: + case RPC_FC_STRUCTPAD2: + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + pMemory += *pFormat - RPC_FC_STRUCTPAD1 + 1; + break; + case RPC_FC_EMBEDDED_COMPLEX: + pMemory += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size = EmbeddedComplexSize(pStubMsg, desc); + m = NdrFreer[*desc & NDR_TABLE_MASK]; + if (m) + { + /* for some reason interface pointers aren't generated as + * RPC_FC_POINTER, but instead as RPC_FC_EMBEDDED_COMPLEX, yet + * they still need the derefencing treatment that pointers are + * given */ + if (*desc == RPC_FC_IP) + m(pStubMsg, *(unsigned char **)pMemory, desc); + else + m(pStubMsg, pMemory, desc); + } + else FIXME("no freer for embedded type %02x\n", *desc); + pMemory += size; + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format 0x%02x\n", *pFormat); + } + pFormat++; + } + + return pMemory; +} + +static unsigned long ComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING desc; + unsigned long size = 0; + + while (*pFormat != RPC_FC_END) { + switch (*pFormat) { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + size += 1; + pStubMsg->Buffer += 1; + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + size += 2; + pStubMsg->Buffer += 2; + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + size += 4; + pStubMsg->Buffer += 4; + break; + case RPC_FC_HYPER: + size += 8; + pStubMsg->Buffer += 8; + break; + case RPC_FC_POINTER: + size += 4; + pStubMsg->Buffer += 4; + if (!pStubMsg->IgnoreEmbeddedPointers) + FIXME("embedded pointers\n"); + break; + case RPC_FC_ALIGNM4: + ALIGN_LENGTH(size, 4); + ALIGN_POINTER(pStubMsg->Buffer, 4); + break; + case RPC_FC_ALIGNM8: + ALIGN_LENGTH(size, 8); + ALIGN_POINTER(pStubMsg->Buffer, 8); + break; + case RPC_FC_STRUCTPAD1: + case RPC_FC_STRUCTPAD2: + case RPC_FC_STRUCTPAD3: + case RPC_FC_STRUCTPAD4: + case RPC_FC_STRUCTPAD5: + case RPC_FC_STRUCTPAD6: + case RPC_FC_STRUCTPAD7: + size += *pFormat - RPC_FC_STRUCTPAD1 + 1; + break; + case RPC_FC_EMBEDDED_COMPLEX: + size += pFormat[1]; + pFormat += 2; + desc = pFormat + *(const SHORT*)pFormat; + size += EmbeddedComplexMemorySize(pStubMsg, desc); + pFormat += 2; + continue; + case RPC_FC_PAD: + break; + default: + FIXME("unhandled format 0x%02x\n", *pFormat); + } + pFormat++; + } + + return size; +} + +/*********************************************************************** + * NdrComplexStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + int pointer_buffer_mark_set = 0; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (!pStubMsg->PointerBufferMark) + { + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + /* save buffer length */ + unsigned long saved_buffer_length = pStubMsg->BufferLength; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->BufferLength = pStubMsg->Buffer - pStubMsg->BufferStart; + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexStructBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->BufferStart + pStubMsg->BufferLength; + TRACE("difference = 0x%x\n", pStubMsg->PointerBufferMark - pStubMsg->Buffer); + pointer_buffer_mark_set = 1; + + /* restore the original buffer length */ + pStubMsg->BufferLength = saved_buffer_length; + } + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + ComplexMarshall(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayMarshall(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; + + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrComplexStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned size = *(const WORD*)(pFormat+2); + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *pMemory; + int pointer_buffer_mark_set = 0; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (!pStubMsg->PointerBufferMark) + { + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + /* save buffer pointer */ + unsigned char *saved_buffer = pStubMsg->Buffer; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexStructMemorySize(pStubMsg, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + TRACE("difference = 0x%lx\n", (unsigned long)(pStubMsg->PointerBufferMark - saved_buffer)); + pointer_buffer_mark_set = 1; + + /* restore the original buffer */ + pStubMsg->Buffer = saved_buffer; + } + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + + if (fMustAlloc || !*ppMemory) + { + *ppMemory = NdrAllocate(pStubMsg, size); + memset(*ppMemory, 0, size); + } + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pMemory = ComplexUnmarshall(pStubMsg, *ppMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayUnmarshall(pStubMsg, &pMemory, conf_array, fMustAlloc); + + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + + return NULL; +} + +/*********************************************************************** + * NdrComplexStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrComplexStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + int pointer_length_set = 0; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + ALIGN_LENGTH(pStubMsg->BufferLength, pFormat[1] + 1); + + if(!pStubMsg->IgnoreEmbeddedPointers && !pStubMsg->PointerLength) + { + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + unsigned long saved_buffer_length = pStubMsg->BufferLength; + + /* get the buffer length after complex struct data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexStructBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerLength = pStubMsg->BufferLength; + pointer_length_set = 1; + TRACE("difference = 0x%lx\n", pStubMsg->PointerLength - saved_buffer_length); + + /* restore the original buffer length */ + pStubMsg->BufferLength = saved_buffer_length; + } + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayBufferSize(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; + + if(pointer_length_set) + { + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } + +} + +/*********************************************************************** + * NdrComplexStructMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrComplexStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned size = *(const WORD*)(pFormat+2); + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + ALIGN_POINTER(pStubMsg->Buffer, pFormat[1] + 1); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + ComplexStructMemorySize(pStubMsg, pFormat); + + if (conf_array) + NdrConformantArrayMemorySize(pStubMsg, conf_array); + + return size; +} + +/*********************************************************************** + * NdrComplexStructFree [RPCRT4.@] + */ +void WINAPI NdrComplexStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + PFORMAT_STRING conf_array = NULL; + PFORMAT_STRING pointer_desc = NULL; + unsigned char *OldMemory = pStubMsg->Memory; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + pFormat += 4; + if (*(const WORD*)pFormat) conf_array = pFormat + *(const WORD*)pFormat; + pFormat += 2; + if (*(const WORD*)pFormat) pointer_desc = pFormat + *(const WORD*)pFormat; + pFormat += 2; + + pStubMsg->Memory = pMemory; + + pMemory = ComplexFree(pStubMsg, pMemory, pFormat, pointer_desc); + + if (conf_array) + NdrConformantArrayFree(pStubMsg, pMemory, conf_array); + + pStubMsg->Memory = OldMemory; +} + +/*********************************************************************** + * NdrConformantArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + unsigned char alignment = pFormat[1] + 1; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + + WriteConformance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + size = safe_multiply(esize, pStubMsg->MaxCount); + memcpy(pStubMsg->Buffer, pMemory, size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrConformantArrayUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + DWORD size, esize = *(const WORD*)(pFormat+2); + unsigned char alignment = pFormat[1] + 1; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ReadConformance(pStubMsg, pFormat+4); + + size = safe_multiply(esize, pStubMsg->MaxCount); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, size); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + memcpy(*ppMemory, pStubMsg->Buffer, size); + + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrConformantArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + DWORD size, esize = *(const WORD*)(pFormat+2); + unsigned char alignment = pFormat[1] + 1; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + + SizeConformance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + size = safe_multiply(esize, pStubMsg->MaxCount); + /* conformance value plus array */ + pStubMsg->BufferLength += size; + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrConformantArrayMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrConformantArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + DWORD size = 0, esize = *(const WORD*)(pFormat+2); + unsigned char alignment = pFormat[1] + 1; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ReadConformance(pStubMsg, pFormat+4); + size = safe_multiply(esize, pStubMsg->MaxCount); + pStubMsg->MemorySize += size; + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += size; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return pStubMsg->MemorySize; +} + +/*********************************************************************** + * NdrConformantArrayFree [RPCRT4.@] + */ +void WINAPI NdrConformantArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pFormat[0] != RPC_FC_CARRAY) FIXME("format=%d\n", pFormat[0]); + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayMarshall [RPCRT4.@] + */ +unsigned char* WINAPI NdrConformantVaryingArrayMarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat ) +{ + ULONG bufsize; + unsigned char alignment = pFormat[1] + 1; + DWORD esize = *(const WORD*)(pFormat+2); + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if (pFormat[0] != RPC_FC_CVARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + + WriteConformance(pStubMsg); + WriteVariance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + memcpy(pStubMsg->Buffer, pMemory + pStubMsg->Offset, bufsize); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += bufsize; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + + +/*********************************************************************** + * NdrConformantVaryingArrayUnmarshall [RPCRT4.@] + */ +unsigned char* WINAPI NdrConformantVaryingArrayUnmarshall( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char** ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc ) +{ + ULONG bufsize, memsize; + unsigned char alignment = pFormat[1] + 1; + DWORD esize = *(const WORD*)(pFormat+2); + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (pFormat[0] != RPC_FC_CVARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + pFormat = ReadConformance(pStubMsg, pFormat+4); + pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + memsize = safe_multiply(esize, pStubMsg->MaxCount); + + if (!*ppMemory || fMustAlloc) + *ppMemory = NdrAllocate(pStubMsg, memsize); + memcpy(*ppMemory + pStubMsg->Offset, pStubMsg->Buffer, bufsize); + pStubMsg->Buffer += bufsize; + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + + +/*********************************************************************** + * NdrConformantVaryingArrayFree [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingArrayFree( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat ) +{ + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (pFormat[0] != RPC_FC_CVARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingArrayBufferSize( PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, PFORMAT_STRING pFormat ) +{ + unsigned char alignment = pFormat[1] + 1; + DWORD esize = *(const WORD*)(pFormat+2); + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if (pFormat[0] != RPC_FC_CVARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + /* compute size */ + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat+4, 0); + /* compute length */ + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + + SizeConformance(pStubMsg); + SizeVariance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + pStubMsg->BufferLength += safe_multiply(esize, pStubMsg->ActualCount); + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + + +/*********************************************************************** + * NdrConformantVaryingArrayMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrConformantVaryingArrayMemorySize( PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat ) +{ + FIXME( "stub\n" ); + return 0; +} + + +/*********************************************************************** + * NdrComplexArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + ULONG i, count, def; + BOOL variance_present; + unsigned char alignment; + int pointer_buffer_mark_set = 0; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (pFormat[0] != RPC_FC_BOGUS_ARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + alignment = pFormat[1] + 1; + + if (!pStubMsg->PointerBufferMark) + { + /* save buffer fields that may be changed by buffer sizer functions + * and that may be needed later on */ + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + unsigned long saved_buffer_length = pStubMsg->BufferLength; + unsigned long saved_max_count = pStubMsg->MaxCount; + unsigned long saved_offset = pStubMsg->Offset; + unsigned long saved_actual_count = pStubMsg->ActualCount; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->BufferLength = pStubMsg->Buffer - pStubMsg->BufferStart; + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexArrayBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->BufferStart + pStubMsg->BufferLength; + TRACE("difference = 0x%x\n", pStubMsg->Buffer - pStubMsg->BufferStart); + pointer_buffer_mark_set = 1; + + /* restore fields */ + pStubMsg->ActualCount = saved_actual_count; + pStubMsg->Offset = saved_offset; + pStubMsg->MaxCount = saved_max_count; + pStubMsg->BufferLength = saved_buffer_length; + } + + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + TRACE("conformance = %ld\n", pStubMsg->MaxCount); + + variance_present = IsConformanceOrVariancePresent(pFormat); + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, pStubMsg->MaxCount); + TRACE("variance = %d\n", pStubMsg->ActualCount); + + WriteConformance(pStubMsg); + if (variance_present) + WriteVariance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) + pMemory = ComplexMarshall(pStubMsg, pMemory, pFormat, NULL); + + STD_OVERFLOW_CHECK(pStubMsg); + + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + + return NULL; +} + +/*********************************************************************** + * NdrComplexArrayUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrComplexArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + ULONG i, count, size; + unsigned char alignment; + unsigned char *pMemory; + unsigned char *saved_buffer; + int pointer_buffer_mark_set = 0; + int saved_ignore_embedded; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if (pFormat[0] != RPC_FC_BOGUS_ARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + alignment = pFormat[1] + 1; + + saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + /* save buffer pointer */ + saved_buffer = pStubMsg->Buffer; + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + pStubMsg->MemorySize = 0; + NdrComplexArrayMemorySize(pStubMsg, pFormat); + size = pStubMsg->MemorySize; + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + TRACE("difference = 0x%lx\n", (unsigned long)(pStubMsg->Buffer - saved_buffer)); + if (!pStubMsg->PointerBufferMark) + { + /* save it for use by embedded pointer code later */ + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pointer_buffer_mark_set = 1; + } + /* restore the original buffer */ + pStubMsg->Buffer = saved_buffer; + + pFormat += 4; + + pFormat = ReadConformance(pStubMsg, pFormat); + pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount); + + if (fMustAlloc || !*ppMemory) + { + *ppMemory = NdrAllocate(pStubMsg, size); + memset(*ppMemory, 0, size); + } + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + pMemory = *ppMemory; + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) + pMemory = ComplexUnmarshall(pStubMsg, pMemory, pFormat, NULL); + + if (pointer_buffer_mark_set) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + + return NULL; +} + +/*********************************************************************** + * NdrComplexArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrComplexArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + ULONG i, count, def; + unsigned char alignment; + BOOL variance_present; + int pointer_length_set = 0; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (pFormat[0] != RPC_FC_BOGUS_ARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + alignment = pFormat[1] + 1; + + if (!pStubMsg->IgnoreEmbeddedPointers && !pStubMsg->PointerLength) + { + /* save buffer fields that may be changed by buffer sizer functions + * and that may be needed later on */ + int saved_ignore_embedded = pStubMsg->IgnoreEmbeddedPointers; + unsigned long saved_buffer_length = pStubMsg->BufferLength; + unsigned long saved_max_count = pStubMsg->MaxCount; + unsigned long saved_offset = pStubMsg->Offset; + unsigned long saved_actual_count = pStubMsg->ActualCount; + + /* get the buffer pointer after complex array data, but before + * pointer data */ + pStubMsg->IgnoreEmbeddedPointers = 1; + NdrComplexArrayBufferSize(pStubMsg, pMemory, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded; + + /* save it for use by embedded pointer code later */ + pStubMsg->PointerLength = pStubMsg->BufferLength; + pointer_length_set = 1; + + /* restore fields */ + pStubMsg->ActualCount = saved_actual_count; + pStubMsg->Offset = saved_offset; + pStubMsg->MaxCount = saved_max_count; + pStubMsg->BufferLength = saved_buffer_length; + } + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + TRACE("conformance = %ld\n", pStubMsg->MaxCount); + SizeConformance(pStubMsg); + + variance_present = IsConformanceOrVariancePresent(pFormat); + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, pStubMsg->MaxCount); + TRACE("variance = %d\n", pStubMsg->ActualCount); + + if (variance_present) + SizeVariance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) + pMemory = ComplexBufferSize(pStubMsg, pMemory, pFormat, NULL); + + if(pointer_length_set) + { + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } +} + +/*********************************************************************** + * NdrComplexArrayMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrComplexArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + ULONG i, count, esize, SavedMemorySize, MemorySize; + unsigned char alignment; + unsigned char *Buffer; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + if (pFormat[0] != RPC_FC_BOGUS_ARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + alignment = pFormat[1] + 1; + + pFormat += 4; + + pFormat = ReadConformance(pStubMsg, pFormat); + pFormat = ReadVariance(pStubMsg, pFormat, pStubMsg->MaxCount); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + SavedMemorySize = pStubMsg->MemorySize; + + Buffer = pStubMsg->Buffer; + pStubMsg->MemorySize = 0; + esize = ComplexStructMemorySize(pStubMsg, pFormat); + pStubMsg->Buffer = Buffer; + + MemorySize = safe_multiply(pStubMsg->MaxCount, esize); + + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) + ComplexStructMemorySize(pStubMsg, pFormat); + + pStubMsg->MemorySize = SavedMemorySize; + + pStubMsg->MemorySize += MemorySize; + return MemorySize; +} + +/*********************************************************************** + * NdrComplexArrayFree [RPCRT4.@] + */ +void WINAPI NdrComplexArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + ULONG i, count, def; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + + if (pFormat[0] != RPC_FC_BOGUS_ARRAY) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + def = *(const WORD*)&pFormat[2]; + pFormat += 4; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, def); + TRACE("conformance = %ld\n", pStubMsg->MaxCount); + + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, pStubMsg->MaxCount); + TRACE("variance = %d\n", pStubMsg->ActualCount); + + count = pStubMsg->ActualCount; + for (i = 0; i < count; i++) + pMemory = ComplexFree(pStubMsg, pMemory, pFormat, NULL); +} + +static ULONG UserMarshalFlags(PMIDL_STUB_MESSAGE pStubMsg) +{ + return MAKELONG(pStubMsg->dwDestContext, + pStubMsg->RpcMsg->DataRepresentation); +} + +#define USER_MARSHAL_PTR_PREFIX \ + ( (DWORD)'U' | ( (DWORD)'s' << 8 ) | \ + ( (DWORD)'e' << 16 ) | ( (DWORD)'r' << 24 ) ) + +/*********************************************************************** + * NdrUserMarshalMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrUserMarshalMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned flags = pFormat[1]; + unsigned index = *(const WORD*)&pFormat[2]; + unsigned char *saved_buffer = NULL; + ULONG uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + NDR_LOCAL_UINT32_WRITE(pStubMsg->Buffer, USER_MARSHAL_PTR_PREFIX); + pStubMsg->Buffer += 4; + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + ALIGN_POINTER(pStubMsg->Buffer, 8); + } + else + ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1); + + pStubMsg->Buffer = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnMarshall( + &uflag, pStubMsg->Buffer, pMemory); + + if (saved_buffer) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrUserMarshalUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrUserMarshalUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned flags = pFormat[1]; + unsigned index = *(const WORD*)&pFormat[2]; + DWORD memsize = *(const WORD*)&pFormat[4]; + unsigned char *saved_buffer = NULL; + ULONG uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + TRACE("index=%d\n", index); + + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + /* skip pointer prefix */ + pStubMsg->Buffer += 4; + if (pStubMsg->PointerBufferMark) + { + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + } + ALIGN_POINTER(pStubMsg->Buffer, 8); + } + else + ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1); + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, memsize); + + pStubMsg->Buffer = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnUnmarshall( + &uflag, pStubMsg->Buffer, *ppMemory); + + if (saved_buffer) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer; + } + + return NULL; +} + +/*********************************************************************** + * NdrUserMarshalBufferSize [RPCRT4.@] + */ +void WINAPI NdrUserMarshalBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned flags = pFormat[1]; + unsigned index = *(const WORD*)&pFormat[2]; + DWORD bufsize = *(const WORD*)&pFormat[6]; + ULONG uflag = UserMarshalFlags(pStubMsg); + unsigned long saved_buffer_length = 0; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + /* skip pointer prefix */ + pStubMsg->BufferLength += 4; + if (pStubMsg->IgnoreEmbeddedPointers) + return; + if (pStubMsg->PointerLength) + { + saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + } + ALIGN_LENGTH(pStubMsg->BufferLength, 8); + } + else + ALIGN_LENGTH(pStubMsg->BufferLength, (flags & 0xf) + 1); + + if (bufsize) { + TRACE("size=%d\n", bufsize); + pStubMsg->BufferLength += bufsize; + } + else + pStubMsg->BufferLength = + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnBufferSize( + &uflag, pStubMsg->BufferLength, pMemory); + + if (saved_buffer_length) + { + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; + } + +} + +/*********************************************************************** + * NdrUserMarshalMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrUserMarshalMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned flags = pFormat[1]; + unsigned index = *(const WORD*)&pFormat[2]; + DWORD memsize = *(const WORD*)&pFormat[4]; + DWORD bufsize = *(const WORD*)&pFormat[6]; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + TRACE("index=%d\n", index); + + pStubMsg->MemorySize += memsize; + + if (flags & USER_MARSHAL_POINTER) + { + ALIGN_POINTER(pStubMsg->Buffer, 4); + /* skip pointer prefix */ + pStubMsg->Buffer += 4; + if (pStubMsg->IgnoreEmbeddedPointers) + return pStubMsg->MemorySize; + ALIGN_POINTER(pStubMsg->Buffer, 8); + } + else + ALIGN_POINTER(pStubMsg->Buffer, (flags & 0xf) + 1); + + if (!bufsize) + FIXME("not implemented for varying buffer size\n"); + + pStubMsg->Buffer += bufsize; + + return pStubMsg->MemorySize; +} + +/*********************************************************************** + * NdrUserMarshalFree [RPCRT4.@] + */ +void WINAPI NdrUserMarshalFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ +/* unsigned flags = pFormat[1]; */ + unsigned index = *(const WORD*)&pFormat[2]; + ULONG uflag = UserMarshalFlags(pStubMsg); + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + TRACE("index=%d\n", index); + + pStubMsg->StubDesc->aUserMarshalQuadruple[index].pfnFree( + &uflag, pMemory); +} + +/*********************************************************************** + * NdrClearOutParameters [RPCRT4.@] + */ +void WINAPI NdrClearOutParameters(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat, + void *ArgAddr) +{ + FIXME("(%p,%p,%p): stub\n", pStubMsg, pFormat, ArgAddr); +} + +/*********************************************************************** + * NdrConvert [RPCRT4.@] + */ +void WINAPI NdrConvert( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat ) +{ + FIXME("(pStubMsg == ^%p, pFormat == ^%p): stub.\n", pStubMsg, pFormat); + /* FIXME: since this stub doesn't do any converting, the proper behavior + is to raise an exception */ +} + +/*********************************************************************** + * NdrConvert2 [RPCRT4.@] + */ +void WINAPI NdrConvert2( PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, LONG NumberParams ) +{ + FIXME("(pStubMsg == ^%p, pFormat == ^%p, NumberParams == %d): stub.\n", + pStubMsg, pFormat, NumberParams); + /* FIXME: since this stub doesn't do any converting, the proper behavior + is to raise an exception */ +} + +#include "pshpack1.h" +typedef struct _NDR_CSTRUCT_FORMAT +{ + unsigned char type; + unsigned char alignment; + unsigned short memory_size; + short offset_to_array_description; +} NDR_CSTRUCT_FORMAT, NDR_CVSTRUCT_FORMAT; +#include "poppack.h" + +/*********************************************************************** + * NdrConformantStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_CSTRUCT_FORMAT *pCStructFormat = (const NDR_CSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCArrayFormat; + ULONG esize, bufsize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CSTRUCT_FORMAT); + if ((pCStructFormat->type != RPC_FC_CPSTRUCT) && (pCStructFormat->type != RPC_FC_CSTRUCT)) + { + ERR("invalid format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + pCArrayFormat = (const unsigned char *)&pCStructFormat->offset_to_array_description + + pCStructFormat->offset_to_array_description; + if (*pCArrayFormat != RPC_FC_CARRAY) + { + ERR("invalid array format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + esize = *(const WORD*)(pCArrayFormat+2); + + ComputeConformance(pStubMsg, pMemory + pCStructFormat->memory_size, + pCArrayFormat + 4, 0); + + WriteConformance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, pCStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCStructFormat->memory_size); + + bufsize = safe_multiply(esize, pStubMsg->MaxCount); + /* copy constant sized part of struct */ + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(pStubMsg->Buffer, pMemory, pCStructFormat->memory_size + bufsize); + pStubMsg->Buffer += pCStructFormat->memory_size + bufsize; + + if (pCStructFormat->type == RPC_FC_CPSTRUCT) + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrConformantStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + const NDR_CSTRUCT_FORMAT *pCStructFormat = (const NDR_CSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCArrayFormat; + ULONG esize, bufsize; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + pFormat += sizeof(NDR_CSTRUCT_FORMAT); + if ((pCStructFormat->type != RPC_FC_CPSTRUCT) && (pCStructFormat->type != RPC_FC_CSTRUCT)) + { + ERR("invalid format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + pCArrayFormat = (const unsigned char *)&pCStructFormat->offset_to_array_description + + pCStructFormat->offset_to_array_description; + if (*pCArrayFormat != RPC_FC_CARRAY) + { + ERR("invalid array format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + esize = *(const WORD*)(pCArrayFormat+2); + + pCArrayFormat = ReadConformance(pStubMsg, pCArrayFormat + 4); + + ALIGN_POINTER(pStubMsg->Buffer, pCStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCStructFormat->memory_size); + + bufsize = safe_multiply(esize, pStubMsg->MaxCount); + /* work out how much memory to allocate if we need to do so */ + if (!*ppMemory || fMustAlloc) + { + SIZE_T size = pCStructFormat->memory_size + bufsize; + *ppMemory = NdrAllocate(pStubMsg, size); + } + + /* now copy the data */ + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(*ppMemory, pStubMsg->Buffer, pCStructFormat->memory_size + bufsize); + pStubMsg->Buffer += pCStructFormat->memory_size + bufsize; + + if (pCStructFormat->type == RPC_FC_CPSTRUCT) + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrConformantStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_CSTRUCT_FORMAT * pCStructFormat = (const NDR_CSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCArrayFormat; + ULONG esize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CSTRUCT_FORMAT); + if ((pCStructFormat->type != RPC_FC_CPSTRUCT) && (pCStructFormat->type != RPC_FC_CSTRUCT)) + { + ERR("invalid format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + pCArrayFormat = (const unsigned char *)&pCStructFormat->offset_to_array_description + + pCStructFormat->offset_to_array_description; + if (*pCArrayFormat != RPC_FC_CARRAY) + { + ERR("invalid array format type %x\n", pCStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + esize = *(const WORD*)(pCArrayFormat+2); + + pCArrayFormat = ComputeConformance(pStubMsg, pMemory + pCStructFormat->memory_size, pCArrayFormat+4, 0); + SizeConformance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, pCStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCStructFormat->memory_size); + + pStubMsg->BufferLength += pCStructFormat->memory_size + + safe_multiply(pStubMsg->MaxCount, esize); + + if (pCStructFormat->type == RPC_FC_CPSTRUCT) + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrConformantStructMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrConformantStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); + return 0; +} + +/*********************************************************************** + * NdrConformantStructFree [RPCRT4.@] + */ +void WINAPI NdrConformantStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); +} + +/*********************************************************************** + * NdrConformantVaryingStructMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantVaryingStructMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize, bufsize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + switch (*pCVArrayFormat) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 4, 0); + pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat, 0); + break; + case RPC_FC_C_CSTRING: + TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + case RPC_FC_C_WSTRING: + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + WriteConformance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + /* write constant sized part */ + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(pStubMsg->Buffer, pMemory, pCVStructFormat->memory_size); + pStubMsg->Buffer += pCVStructFormat->memory_size; + + WriteVariance(pStubMsg); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + /* write array part */ + memcpy(pStubMsg->Buffer, pMemory + pCVStructFormat->memory_size, bufsize); + pStubMsg->Buffer += bufsize; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrConformantVaryingStructUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrConformantVaryingStructUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize, bufsize; + unsigned char cvarray_type; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + cvarray_type = *pCVArrayFormat; + switch (cvarray_type) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 4); + break; + case RPC_FC_C_CSTRING: + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + case RPC_FC_C_WSTRING: + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + /* work out how much memory to allocate if we need to do so */ + if (!*ppMemory || fMustAlloc) + { + SIZE_T size = pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->MaxCount); + *ppMemory = NdrAllocate(pStubMsg, size); + } + + /* copy the constant data */ + pStubMsg->BufferMark = pStubMsg->Buffer; + memcpy(*ppMemory, pStubMsg->Buffer, pCVStructFormat->memory_size); + pStubMsg->Buffer += pCVStructFormat->memory_size; + + pCVArrayFormat = ReadVariance(pStubMsg, pCVArrayFormat, pStubMsg->MaxCount); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + if ((cvarray_type == RPC_FC_C_CSTRING) || + (cvarray_type == RPC_FC_C_WSTRING)) + { + ULONG i; + /* strings must always have null terminating bytes */ + if (bufsize < esize) + { + ERR("invalid string length of %d\n", pStubMsg->ActualCount); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + for (i = bufsize - esize; i < bufsize; i++) + if (pStubMsg->Buffer[i] != 0) + { + ERR("string not null-terminated at byte position %d, data is 0x%x\n", + i, pStubMsg->Buffer[i]); + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + } + + /* copy the array data */ + memcpy(*ppMemory + pCVStructFormat->memory_size, pStubMsg->Buffer, + bufsize); + pStubMsg->Buffer += bufsize; + + if (cvarray_type == RPC_FC_C_CSTRING) + TRACE("string=%s\n", debugstr_a((char *)(*ppMemory + pCVStructFormat->memory_size))); + else if (cvarray_type == RPC_FC_C_WSTRING) + TRACE("string=%s\n", debugstr_w((WCHAR *)(*ppMemory + pCVStructFormat->memory_size))); + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrConformantVaryingStructBufferSize [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingStructBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + switch (*pCVArrayFormat) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 4, 0); + pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat, 0); + break; + case RPC_FC_C_CSTRING: + TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + case RPC_FC_C_WSTRING: + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + SizeConformance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + pStubMsg->BufferLength += pCVStructFormat->memory_size; + SizeVariance(pStubMsg); + pStubMsg->BufferLength += safe_multiply(pStubMsg->MaxCount, esize); + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrConformantVaryingStructMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrConformantVaryingStructMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize; + unsigned char cvarray_type; + + TRACE("(%p, %p)\n", pStubMsg, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + cvarray_type = *pCVArrayFormat; + switch (cvarray_type) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 4); + break; + case RPC_FC_C_CSTRING: + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + case RPC_FC_C_WSTRING: + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ReadConformance(pStubMsg, pCVArrayFormat + 2); + else + pCVArrayFormat = ReadConformance(pStubMsg, NULL); + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + ALIGN_POINTER(pStubMsg->Buffer, pCVStructFormat->alignment + 1); + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + pStubMsg->Buffer += pCVStructFormat->memory_size; + pCVArrayFormat = ReadVariance(pStubMsg, pCVArrayFormat, pStubMsg->MaxCount); + pStubMsg->Buffer += pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->ActualCount); + + pStubMsg->MemorySize += pCVStructFormat->memory_size + safe_multiply(esize, pStubMsg->MaxCount); + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return pCVStructFormat->memory_size + pStubMsg->MaxCount * esize; +} + +/*********************************************************************** + * NdrConformantVaryingStructFree [RPCRT4.@] + */ +void WINAPI NdrConformantVaryingStructFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_CVSTRUCT_FORMAT *pCVStructFormat = (const NDR_CVSTRUCT_FORMAT *)pFormat; + PFORMAT_STRING pCVArrayFormat; + ULONG esize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + pFormat += sizeof(NDR_CVSTRUCT_FORMAT); + if (pCVStructFormat->type != RPC_FC_CVSTRUCT) + { + ERR("invalid format type %x\n", pCVStructFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + pCVArrayFormat = (const unsigned char *)&pCVStructFormat->offset_to_array_description + + pCVStructFormat->offset_to_array_description; + switch (*pCVArrayFormat) + { + case RPC_FC_CVARRAY: + esize = *(const WORD*)(pCVArrayFormat+2); + + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 4, 0); + pCVArrayFormat = ComputeVariance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat, 0); + break; + case RPC_FC_C_CSTRING: + TRACE("string=%s\n", debugstr_a((char*)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlen((char*)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(char); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + case RPC_FC_C_WSTRING: + TRACE("string=%s\n", debugstr_w((LPWSTR)pMemory + pCVStructFormat->memory_size)); + pStubMsg->ActualCount = strlenW((LPWSTR)pMemory + pCVStructFormat->memory_size)+1; + esize = sizeof(WCHAR); + if (pCVArrayFormat[1] == RPC_FC_STRING_SIZED) + pCVArrayFormat = ComputeConformance(pStubMsg, pMemory + pCVStructFormat->memory_size, + pCVArrayFormat + 2, 0); + else + pStubMsg->MaxCount = pStubMsg->ActualCount; + break; + default: + ERR("invalid array format type %x\n", *pCVArrayFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + TRACE("memory_size = %d\n", pCVStructFormat->memory_size); + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); +} + +#include "pshpack1.h" +typedef struct +{ + unsigned char type; + unsigned char alignment; + unsigned short total_size; +} NDR_SMFARRAY_FORMAT; + +typedef struct +{ + unsigned char type; + unsigned char alignment; + unsigned long total_size; +} NDR_LGFARRAY_FORMAT; +#include "poppack.h" + +/*********************************************************************** + * NdrFixedArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrFixedArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + unsigned long total_size; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + ALIGN_POINTER(pStubMsg->Buffer, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + + memcpy(pStubMsg->Buffer, pMemory, total_size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += total_size; + + pFormat = EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + return NULL; +} + +/*********************************************************************** + * NdrFixedArrayUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrFixedArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + unsigned long total_size; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + ALIGN_POINTER(pStubMsg->Buffer, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, total_size); + memcpy(*ppMemory, pStubMsg->Buffer, total_size); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += total_size; + + pFormat = EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrFixedArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrFixedArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + unsigned long total_size; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + ALIGN_LENGTH(pStubMsg->BufferLength, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + pStubMsg->BufferLength += total_size; + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrFixedArrayMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrFixedArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + ULONG total_size; + + TRACE("(%p, %p)\n", pStubMsg, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + ALIGN_POINTER(pStubMsg->Buffer, pSmFArrayFormat->alignment + 1); + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + { + total_size = pSmFArrayFormat->total_size; + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + } + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + total_size = pLgFArrayFormat->total_size; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += total_size; + pStubMsg->MemorySize += total_size; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return total_size; +} + +/*********************************************************************** + * NdrFixedArrayFree [RPCRT4.@] + */ +void WINAPI NdrFixedArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const NDR_SMFARRAY_FORMAT *pSmFArrayFormat = (const NDR_SMFARRAY_FORMAT *)pFormat; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pSmFArrayFormat->type != RPC_FC_SMFARRAY) && + (pSmFArrayFormat->type != RPC_FC_LGFARRAY)) + { + ERR("invalid format type %x\n", pSmFArrayFormat->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + if (pSmFArrayFormat->type == RPC_FC_SMFARRAY) + pFormat = (const unsigned char *)(pSmFArrayFormat + 1); + else + { + const NDR_LGFARRAY_FORMAT *pLgFArrayFormat = (const NDR_LGFARRAY_FORMAT *)pFormat; + pFormat = (const unsigned char *)(pLgFArrayFormat + 1); + } + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrVaryingArrayMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrVaryingArrayMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char alignment; + DWORD elements, esize; + ULONG bufsize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + if ((pStubMsg->ActualCount > elements) || + (pStubMsg->ActualCount + pStubMsg->Offset > elements)) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return NULL; + } + + WriteVariance(pStubMsg); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + memcpy(pStubMsg->Buffer, pMemory + pStubMsg->Offset, bufsize); + pStubMsg->BufferMark = pStubMsg->Buffer; + pStubMsg->Buffer += bufsize; + + EmbeddedPointerMarshall(pStubMsg, pMemory, pFormat); + + STD_OVERFLOW_CHECK(pStubMsg); + + return NULL; +} + +/*********************************************************************** + * NdrVaryingArrayUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrVaryingArrayUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned char alignment; + DWORD size, elements, esize; + ULONG bufsize; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + size = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + size = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ReadVariance(pStubMsg, pFormat, elements); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + bufsize = safe_multiply(esize, pStubMsg->ActualCount); + + if (!*ppMemory || fMustAlloc) + *ppMemory = NdrAllocate(pStubMsg, size); + memcpy(*ppMemory + pStubMsg->Offset, pStubMsg->Buffer, bufsize); + pStubMsg->Buffer += bufsize; + + EmbeddedPointerUnmarshall(pStubMsg, ppMemory, pFormat, fMustAlloc); + + return NULL; +} + +/*********************************************************************** + * NdrVaryingArrayBufferSize [RPCRT4.@] + */ +void WINAPI NdrVaryingArrayBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char alignment; + DWORD elements, esize; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + if ((pStubMsg->ActualCount > elements) || + (pStubMsg->ActualCount + pStubMsg->Offset > elements)) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return; + } + + SizeVariance(pStubMsg); + + ALIGN_LENGTH(pStubMsg->BufferLength, alignment); + + pStubMsg->BufferLength += safe_multiply(esize, pStubMsg->ActualCount); + + EmbeddedPointerBufferSize(pStubMsg, pMemory, pFormat); +} + +/*********************************************************************** + * NdrVaryingArrayMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrVaryingArrayMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned char alignment; + DWORD size, elements, esize; + + TRACE("(%p, %p)\n", pStubMsg, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + size = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + size = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + esize = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + + pFormat = ReadVariance(pStubMsg, pFormat, elements); + + ALIGN_POINTER(pStubMsg->Buffer, alignment); + + pStubMsg->Buffer += safe_multiply(esize, pStubMsg->ActualCount); + pStubMsg->MemorySize += size; + + EmbeddedPointerMemorySize(pStubMsg, pFormat); + + return pStubMsg->MemorySize; +} + +/*********************************************************************** + * NdrVaryingArrayFree [RPCRT4.@] + */ +void WINAPI NdrVaryingArrayFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char alignment; + DWORD elements; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + + if ((pFormat[0] != RPC_FC_SMVARRAY) && + (pFormat[0] != RPC_FC_LGVARRAY)) + { + ERR("invalid format type %x\n", pFormat[0]); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return; + } + + alignment = pFormat[1] + 1; + + if (pFormat[0] == RPC_FC_SMVARRAY) + { + pFormat += 2; + pFormat += sizeof(WORD); + elements = *(const WORD*)pFormat; + pFormat += sizeof(WORD); + } + else + { + pFormat += 2; + pFormat += sizeof(DWORD); + elements = *(const DWORD*)pFormat; + pFormat += sizeof(DWORD); + } + + pFormat += sizeof(WORD); + + pFormat = ComputeVariance(pStubMsg, pMemory, pFormat, 0); + if ((pStubMsg->ActualCount > elements) || + (pStubMsg->ActualCount + pStubMsg->Offset > elements)) + { + RpcRaiseException(RPC_S_INVALID_BOUND); + return; + } + + EmbeddedPointerFree(pStubMsg, pMemory, pFormat); +} + +static ULONG get_discriminant(unsigned char fc, unsigned char *pMemory) +{ + switch (fc) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + return *(UCHAR *)pMemory; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_ENUM16: + return *(USHORT *)pMemory; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + return *(ULONG *)pMemory; + default: + FIXME("Unhandled base type: 0x%02x\n", fc); + return 0; + } +} + +static PFORMAT_STRING get_arm_offset_from_union_arm_selector(PMIDL_STUB_MESSAGE pStubMsg, + unsigned long discriminant, + PFORMAT_STRING pFormat) +{ + unsigned short num_arms, arm, type; + + num_arms = *(const SHORT*)pFormat & 0x0fff; + pFormat += 2; + for(arm = 0; arm < num_arms; arm++) + { + if(discriminant == *(const ULONG*)pFormat) + { + pFormat += 4; + break; + } + pFormat += 6; + } + + type = *(const unsigned short*)pFormat; + TRACE("type %04x\n", type); + if(arm == num_arms) /* default arm extras */ + { + if(type == 0xffff) + { + ERR("no arm for 0x%lx and no default case\n", discriminant); + RpcRaiseException(RPC_S_INVALID_TAG); + return NULL; + } + if(type == 0) + { + TRACE("falling back to empty default case for 0x%lx\n", discriminant); + return NULL; + } + } + return pFormat; +} + +static unsigned char *union_arm_marshall(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, ULONG discriminant, PFORMAT_STRING pFormat) +{ + unsigned short type; + + pFormat += 2; + + pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat); + if(!pFormat) + return NULL; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + unsigned char basetype = LOBYTE(type); + return NdrBaseTypeMarshall(pStubMsg, pMemory, &basetype); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_MARSHALL m = NdrMarshaller[*desc & NDR_TABLE_MASK]; + if (m) + { + unsigned char *saved_buffer = NULL; + int pointer_buffer_mark_set = 0; + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + ALIGN_POINTER(pStubMsg->Buffer, 4); + saved_buffer = pStubMsg->Buffer; + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + + PointerMarshall(pStubMsg, saved_buffer, *(unsigned char **)pMemory, desc); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } + break; + default: + m(pStubMsg, pMemory, desc); + } + } + else FIXME("no marshaller for embedded type %02x\n", *desc); + } + return NULL; +} + +static unsigned char *union_arm_unmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + ULONG discriminant, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned short type; + + pFormat += 2; + + pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat); + if(!pFormat) + return NULL; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + unsigned char basetype = LOBYTE(type); + return NdrBaseTypeUnmarshall(pStubMsg, ppMemory, &basetype, fMustAlloc); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_UNMARSHALL m = NdrUnmarshaller[*desc & NDR_TABLE_MASK]; + if (m) + { + unsigned char *saved_buffer = NULL; + int pointer_buffer_mark_set = 0; + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + **(void***)ppMemory = NULL; + ALIGN_POINTER(pStubMsg->Buffer, 4); + saved_buffer = pStubMsg->Buffer; + if (pStubMsg->PointerBufferMark) + { + pStubMsg->Buffer = pStubMsg->PointerBufferMark; + pStubMsg->PointerBufferMark = NULL; + pointer_buffer_mark_set = 1; + } + else + pStubMsg->Buffer += 4; /* for pointer ID */ + + PointerUnmarshall(pStubMsg, saved_buffer, *(unsigned char ***)ppMemory, desc, fMustAlloc); + if (pointer_buffer_mark_set) + { + STD_OVERFLOW_CHECK(pStubMsg); + pStubMsg->PointerBufferMark = pStubMsg->Buffer; + pStubMsg->Buffer = saved_buffer + 4; + } + break; + default: + m(pStubMsg, ppMemory, desc, fMustAlloc); + } + } + else FIXME("no marshaller for embedded type %02x\n", *desc); + } + return NULL; +} + +static void union_arm_buffer_size(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + ULONG discriminant, + PFORMAT_STRING pFormat) +{ + unsigned short type; + + pFormat += 2; + + pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat); + if(!pFormat) + return; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + unsigned char basetype = LOBYTE(type); + NdrBaseTypeBufferSize(pStubMsg, pMemory, &basetype); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_BUFFERSIZE m = NdrBufferSizer[*desc & NDR_TABLE_MASK]; + if (m) + { + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += 4; /* for pointer ID */ + if (!pStubMsg->IgnoreEmbeddedPointers) + { + int saved_buffer_length = pStubMsg->BufferLength; + pStubMsg->BufferLength = pStubMsg->PointerLength; + pStubMsg->PointerLength = 0; + if(!pStubMsg->BufferLength) + ERR("BufferLength == 0??\n"); + PointerBufferSize(pStubMsg, *(unsigned char **)pMemory, desc); + pStubMsg->PointerLength = pStubMsg->BufferLength; + pStubMsg->BufferLength = saved_buffer_length; + } + break; + default: + m(pStubMsg, pMemory, desc); + } + } + else FIXME("no buffersizer for embedded type %02x\n", *desc); + } +} + +static ULONG union_arm_memory_size(PMIDL_STUB_MESSAGE pStubMsg, + ULONG discriminant, + PFORMAT_STRING pFormat) +{ + unsigned short type, size; + + size = *(const unsigned short*)pFormat; + pStubMsg->Memory += size; + pFormat += 2; + + pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat); + if(!pFormat) + return 0; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) == 0x8000) + { + return NdrBaseTypeMemorySize(pStubMsg, pFormat); + } + else + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_MEMORYSIZE m = NdrMemorySizer[*desc & NDR_TABLE_MASK]; + unsigned char *saved_buffer; + if (m) + { + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + ALIGN_POINTER(pStubMsg->Buffer, 4); + saved_buffer = pStubMsg->Buffer; + pStubMsg->Buffer += 4; + ALIGN_LENGTH(pStubMsg->MemorySize, 4); + pStubMsg->MemorySize += 4; + if (!pStubMsg->IgnoreEmbeddedPointers) + PointerMemorySize(pStubMsg, saved_buffer, pFormat); + break; + default: + return m(pStubMsg, desc); + } + } + else FIXME("no marshaller for embedded type %02x\n", *desc); + } + + TRACE("size %d\n", size); + return size; +} + +static void union_arm_free(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + ULONG discriminant, + PFORMAT_STRING pFormat) +{ + unsigned short type; + + pFormat += 2; + + pFormat = get_arm_offset_from_union_arm_selector(pStubMsg, discriminant, pFormat); + if(!pFormat) + return; + + type = *(const unsigned short*)pFormat; + if((type & 0xff00) != 0x8000) + { + PFORMAT_STRING desc = pFormat + *(const SHORT*)pFormat; + NDR_FREE m = NdrFreer[*desc & NDR_TABLE_MASK]; + if (m) + { + switch(*desc) + { + case RPC_FC_RP: + case RPC_FC_UP: + case RPC_FC_OP: + case RPC_FC_FP: + PointerFree(pStubMsg, *(unsigned char **)pMemory, desc); + break; + default: + m(pStubMsg, pMemory, desc); + } + } + else FIXME("no freer for embedded type %02x\n", *desc); + } +} + +/*********************************************************************** + * NdrEncapsulatedUnionMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char switch_type; + unsigned char increment; + ULONG switch_value; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + + switch_type = *pFormat & 0xf; + increment = (*pFormat & 0xf0) >> 4; + pFormat++; + + ALIGN_POINTER(pStubMsg->Buffer, increment); + + switch_value = get_discriminant(switch_type, pMemory); + TRACE("got switch value 0x%x\n", switch_value); + + NdrBaseTypeMarshall(pStubMsg, pMemory, &switch_type); + pMemory += increment; + + return union_arm_marshall(pStubMsg, pMemory, switch_value, pFormat); +} + +/*********************************************************************** + * NdrEncapsulatedUnionUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + unsigned char switch_type; + unsigned char increment; + ULONG switch_value; + unsigned short size; + unsigned char *pMemoryArm; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + pFormat++; + + switch_type = *pFormat & 0xf; + increment = (*pFormat & 0xf0) >> 4; + pFormat++; + + ALIGN_POINTER(pStubMsg->Buffer, increment); + switch_value = get_discriminant(switch_type, pStubMsg->Buffer); + TRACE("got switch value 0x%x\n", switch_value); + + size = *(const unsigned short*)pFormat + increment; + if(!*ppMemory || fMustAlloc) + *ppMemory = NdrAllocate(pStubMsg, size); + + NdrBaseTypeUnmarshall(pStubMsg, ppMemory, &switch_type, FALSE); + pMemoryArm = *ppMemory + increment; + + return union_arm_unmarshall(pStubMsg, &pMemoryArm, switch_value, pFormat, fMustAlloc); +} + +/*********************************************************************** + * NdrEncapsulatedUnionBufferSize [RPCRT4.@] + */ +void WINAPI NdrEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char switch_type; + unsigned char increment; + ULONG switch_value; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + + switch_type = *pFormat & 0xf; + increment = (*pFormat & 0xf0) >> 4; + pFormat++; + + ALIGN_LENGTH(pStubMsg->BufferLength, increment); + switch_value = get_discriminant(switch_type, pMemory); + TRACE("got switch value 0x%x\n", switch_value); + + /* Add discriminant size */ + NdrBaseTypeBufferSize(pStubMsg, (unsigned char *)&switch_value, &switch_type); + pMemory += increment; + + union_arm_buffer_size(pStubMsg, pMemory, switch_value, pFormat); +} + +/*********************************************************************** + * NdrEncapsulatedUnionMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + unsigned char switch_type; + unsigned char increment; + ULONG switch_value; + + switch_type = *pFormat & 0xf; + increment = (*pFormat & 0xf0) >> 4; + pFormat++; + + ALIGN_POINTER(pStubMsg->Buffer, increment); + switch_value = get_discriminant(switch_type, pStubMsg->Buffer); + TRACE("got switch value 0x%x\n", switch_value); + + pStubMsg->Memory += increment; + + return increment + union_arm_memory_size(pStubMsg, switch_value, pFormat + *(const SHORT*)pFormat); +} + +/*********************************************************************** + * NdrEncapsulatedUnionFree [RPCRT4.@] + */ +void WINAPI NdrEncapsulatedUnionFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char switch_type; + unsigned char increment; + ULONG switch_value; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + + switch_type = *pFormat & 0xf; + increment = (*pFormat & 0xf0) >> 4; + pFormat++; + + switch_value = get_discriminant(switch_type, pMemory); + TRACE("got switch value 0x%x\n", switch_value); + + pMemory += increment; + + return union_arm_free(pStubMsg, pMemory, switch_value, pFormat); +} + +/*********************************************************************** + * NdrNonEncapsulatedUnionMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrNonEncapsulatedUnionMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char switch_type; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + + switch_type = *pFormat; + pFormat++; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, 0); + TRACE("got switch value 0x%lx\n", pStubMsg->MaxCount); + /* Marshall discriminant */ + NdrBaseTypeMarshall(pStubMsg, (unsigned char *)&pStubMsg->MaxCount, &switch_type); + + return union_arm_marshall(pStubMsg, pMemory, pStubMsg->MaxCount, pFormat + *(const SHORT*)pFormat); +} + +static long unmarshall_discriminant(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING *ppFormat) +{ + long discriminant = 0; + + switch(**ppFormat) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + discriminant = *(UCHAR *)pStubMsg->Buffer; + pStubMsg->Buffer += sizeof(UCHAR); + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); + discriminant = *(USHORT *)pStubMsg->Buffer; + pStubMsg->Buffer += sizeof(USHORT); + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG)); + discriminant = *(ULONG *)pStubMsg->Buffer; + pStubMsg->Buffer += sizeof(ULONG); + break; + default: + FIXME("Unhandled base type: 0x%02x\n", **ppFormat); + } + (*ppFormat)++; + + if (pStubMsg->fHasNewCorrDesc) + *ppFormat += 6; + else + *ppFormat += 4; + return discriminant; +} + +/********************************************************************** + * NdrNonEncapsulatedUnionUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrNonEncapsulatedUnionUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + long discriminant; + unsigned short size; + + TRACE("(%p, %p, %p, %d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + pFormat++; + + /* Unmarshall discriminant */ + discriminant = unmarshall_discriminant(pStubMsg, &pFormat); + TRACE("unmarshalled discriminant %lx\n", discriminant); + + pFormat += *(const SHORT*)pFormat; + + size = *(const unsigned short*)pFormat; + + if(!*ppMemory || fMustAlloc) + *ppMemory = NdrAllocate(pStubMsg, size); + + return union_arm_unmarshall(pStubMsg, ppMemory, discriminant, pFormat, fMustAlloc); +} + +/*********************************************************************** + * NdrNonEncapsulatedUnionBufferSize [RPCRT4.@] + */ +void WINAPI NdrNonEncapsulatedUnionBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + unsigned char switch_type; + + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + + switch_type = *pFormat; + pFormat++; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, 0); + TRACE("got switch value 0x%lx\n", pStubMsg->MaxCount); + /* Add discriminant size */ + NdrBaseTypeBufferSize(pStubMsg, (unsigned char *)&pStubMsg->MaxCount, &switch_type); + + union_arm_buffer_size(pStubMsg, pMemory, pStubMsg->MaxCount, pFormat + *(const SHORT*)pFormat); +} + +/*********************************************************************** + * NdrNonEncapsulatedUnionMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrNonEncapsulatedUnionMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + ULONG discriminant; + + pFormat++; + /* Unmarshall discriminant */ + discriminant = unmarshall_discriminant(pStubMsg, &pFormat); + TRACE("unmarshalled discriminant 0x%x\n", discriminant); + + return union_arm_memory_size(pStubMsg, discriminant, pFormat + *(const SHORT*)pFormat); +} + +/*********************************************************************** + * NdrNonEncapsulatedUnionFree [RPCRT4.@] + */ +void WINAPI NdrNonEncapsulatedUnionFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("(%p, %p, %p)\n", pStubMsg, pMemory, pFormat); + pFormat++; + pFormat++; + + pFormat = ComputeConformance(pStubMsg, pMemory, pFormat, 0); + TRACE("got switch value 0x%lx\n", pStubMsg->MaxCount); + + return union_arm_free(pStubMsg, pMemory, pStubMsg->MaxCount, pFormat + *(const SHORT*)pFormat); +} + +/*********************************************************************** + * NdrByteCountPointerMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrByteCountPointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); + return NULL; +} + +/*********************************************************************** + * NdrByteCountPointerUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrByteCountPointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + FIXME("stub\n"); + return NULL; +} + +/*********************************************************************** + * NdrByteCountPointerBufferSize [RPCRT4.@] + */ +void WINAPI NdrByteCountPointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); +} + +/*********************************************************************** + * NdrByteCountPointerMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrByteCountPointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); + return 0; +} + +/*********************************************************************** + * NdrByteCountPointerFree [RPCRT4.@] + */ +void WINAPI NdrByteCountPointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); +} + +/*********************************************************************** + * NdrXmitOrRepAsMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrXmitOrRepAsMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); + return NULL; +} + +/*********************************************************************** + * NdrXmitOrRepAsUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrXmitOrRepAsUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + FIXME("stub\n"); + return NULL; +} + +/*********************************************************************** + * NdrXmitOrRepAsBufferSize [RPCRT4.@] + */ +void WINAPI NdrXmitOrRepAsBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); +} + +/*********************************************************************** + * NdrXmitOrRepAsMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrXmitOrRepAsMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); + return 0; +} + +/*********************************************************************** + * NdrXmitOrRepAsFree [RPCRT4.@] + */ +void WINAPI NdrXmitOrRepAsFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("stub\n"); +} + +#include "pshpack1.h" +typedef struct +{ + unsigned char type; + unsigned char flags_type; /* flags in upper nibble, type in lower nibble */ + ULONG low_value; + ULONG high_value; +} NDR_RANGE; +#include "poppack.h" + +/*********************************************************************** + * NdrRangeMarshall [internal] + */ +unsigned char *WINAPI NdrRangeMarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + + base_type = pRange->flags_type & 0xf; + + return NdrBaseTypeMarshall(pStubMsg, pMemory, &base_type); +} + +/*********************************************************************** + * NdrRangeUnmarshall + */ +unsigned char *WINAPI NdrRangeUnmarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + TRACE("pStubMsg: %p, ppMemory: %p, type: 0x%02x, fMustAlloc: %s\n", pStubMsg, ppMemory, *pFormat, fMustAlloc ? "true" : "false"); + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return NULL; + } + base_type = pRange->flags_type & 0xf; + + TRACE("base_type = 0x%02x, low_value = %d, high_value = %d\n", + base_type, pRange->low_value, pRange->high_value); + +#define RANGE_UNMARSHALL(type, format_spec) \ + do \ + { \ + ALIGN_POINTER(pStubMsg->Buffer, sizeof(type)); \ + if (fMustAlloc || !*ppMemory) \ + *ppMemory = NdrAllocate(pStubMsg, sizeof(type)); \ + if ((*(type *)pStubMsg->Buffer < (type)pRange->low_value) || \ + (*(type *)pStubMsg->Buffer > (type)pRange->high_value)) \ + { \ + ERR("value exceeded bounds: " format_spec ", low: " format_spec ", high: " format_spec "\n", \ + *(type *)pStubMsg->Buffer, (type)pRange->low_value, \ + (type)pRange->high_value); \ + RpcRaiseException(RPC_S_INVALID_BOUND); \ + return NULL; \ + } \ + TRACE("*ppMemory: %p\n", *ppMemory); \ + **(type **)ppMemory = *(type *)pStubMsg->Buffer; \ + pStubMsg->Buffer += sizeof(type); \ + } while (0) + + switch(base_type) + { + case RPC_FC_CHAR: + case RPC_FC_SMALL: + RANGE_UNMARSHALL(UCHAR, "%d"); + TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory); + break; + case RPC_FC_BYTE: + case RPC_FC_USMALL: + RANGE_UNMARSHALL(CHAR, "%u"); + TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory); + break; + case RPC_FC_WCHAR: /* FIXME: valid? */ + case RPC_FC_USHORT: + RANGE_UNMARSHALL(USHORT, "%u"); + TRACE("value: 0x%04x\n", **(USHORT **)ppMemory); + break; + case RPC_FC_SHORT: + RANGE_UNMARSHALL(SHORT, "%d"); + TRACE("value: 0x%04x\n", **(USHORT **)ppMemory); + break; + case RPC_FC_LONG: + RANGE_UNMARSHALL(LONG, "%d"); + TRACE("value: 0x%08x\n", **(ULONG **)ppMemory); + break; + case RPC_FC_ULONG: + RANGE_UNMARSHALL(ULONG, "%u"); + TRACE("value: 0x%08x\n", **(ULONG **)ppMemory); + break; + case RPC_FC_ENUM16: + case RPC_FC_ENUM32: + FIXME("Unhandled enum type\n"); + break; + case RPC_FC_ERROR_STATUS_T: /* FIXME: valid? */ + case RPC_FC_FLOAT: + case RPC_FC_DOUBLE: + case RPC_FC_HYPER: + default: + ERR("invalid range base type: 0x%02x\n", base_type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + return NULL; +} + +/*********************************************************************** + * NdrRangeBufferSize [internal] + */ +void WINAPI NdrRangeBufferSize( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + base_type = pRange->flags_type & 0xf; + + NdrBaseTypeBufferSize(pStubMsg, pMemory, &base_type); +} + +/*********************************************************************** + * NdrRangeMemorySize [internal] + */ +ULONG WINAPI NdrRangeMemorySize( + PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + NDR_RANGE *pRange = (NDR_RANGE *)pFormat; + unsigned char base_type; + + if (pRange->type != RPC_FC_RANGE) + { + ERR("invalid format type %x\n", pRange->type); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + return 0; + } + base_type = pRange->flags_type & 0xf; + + return NdrBaseTypeMemorySize(pStubMsg, &base_type); +} + +/*********************************************************************** + * NdrRangeFree [internal] + */ +void WINAPI NdrRangeFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p pMemory %p type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + /* nothing to do */ +} + +/*********************************************************************** + * NdrBaseTypeMarshall [internal] + */ +static unsigned char *WINAPI NdrBaseTypeMarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + switch(*pFormat) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + *(UCHAR *)pStubMsg->Buffer = *(UCHAR *)pMemory; + pStubMsg->Buffer += sizeof(UCHAR); + TRACE("value: 0x%02x\n", *(UCHAR *)pMemory); + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); + *(USHORT *)pStubMsg->Buffer = *(USHORT *)pMemory; + pStubMsg->Buffer += sizeof(USHORT); + TRACE("value: 0x%04x\n", *(USHORT *)pMemory); + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ERROR_STATUS_T: + case RPC_FC_ENUM32: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONG)); + *(ULONG *)pStubMsg->Buffer = *(ULONG *)pMemory; + pStubMsg->Buffer += sizeof(ULONG); + TRACE("value: 0x%08x\n", *(ULONG *)pMemory); + break; + case RPC_FC_FLOAT: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(float)); + *(float *)pStubMsg->Buffer = *(float *)pMemory; + pStubMsg->Buffer += sizeof(float); + break; + case RPC_FC_DOUBLE: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(double)); + *(double *)pStubMsg->Buffer = *(double *)pMemory; + pStubMsg->Buffer += sizeof(double); + break; + case RPC_FC_HYPER: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(ULONGLONG)); + *(ULONGLONG *)pStubMsg->Buffer = *(ULONGLONG *)pMemory; + pStubMsg->Buffer += sizeof(ULONGLONG); + TRACE("value: %s\n", wine_dbgstr_longlong(*(ULONGLONG*)pMemory)); + break; + case RPC_FC_ENUM16: + /* only 16-bits on the wire, so do a sanity check */ + if (*(UINT *)pMemory > USHRT_MAX) + RpcRaiseException(RPC_X_ENUM_VALUE_OUT_OF_RANGE); + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); + *(USHORT *)pStubMsg->Buffer = *(UINT *)pMemory; + pStubMsg->Buffer += sizeof(USHORT); + TRACE("value: 0x%04x\n", *(UINT *)pMemory); + break; + default: + FIXME("Unhandled base type: 0x%02x\n", *pFormat); + } + + STD_OVERFLOW_CHECK(pStubMsg); + + /* FIXME: what is the correct return value? */ + return NULL; +} + +/*********************************************************************** + * NdrBaseTypeUnmarshall [internal] + */ +static unsigned char *WINAPI NdrBaseTypeUnmarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + TRACE("pStubMsg: %p, ppMemory: %p, type: 0x%02x, fMustAlloc: %s\n", pStubMsg, ppMemory, *pFormat, fMustAlloc ? "true" : "false"); + +#define BASE_TYPE_UNMARSHALL(type) \ + ALIGN_POINTER(pStubMsg->Buffer, sizeof(type)); \ + if (fMustAlloc || !*ppMemory) \ + *ppMemory = NdrAllocate(pStubMsg, sizeof(type)); \ + TRACE("*ppMemory: %p\n", *ppMemory); \ + **(type **)ppMemory = *(type *)pStubMsg->Buffer; \ + pStubMsg->Buffer += sizeof(type); + + switch(*pFormat) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + BASE_TYPE_UNMARSHALL(UCHAR); + TRACE("value: 0x%02x\n", **(UCHAR **)ppMemory); + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + BASE_TYPE_UNMARSHALL(USHORT); + TRACE("value: 0x%04x\n", **(USHORT **)ppMemory); + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ERROR_STATUS_T: + case RPC_FC_ENUM32: + BASE_TYPE_UNMARSHALL(ULONG); + TRACE("value: 0x%08x\n", **(ULONG **)ppMemory); + break; + case RPC_FC_FLOAT: + BASE_TYPE_UNMARSHALL(float); + TRACE("value: %f\n", **(float **)ppMemory); + break; + case RPC_FC_DOUBLE: + BASE_TYPE_UNMARSHALL(double); + TRACE("value: %f\n", **(double **)ppMemory); + break; + case RPC_FC_HYPER: + BASE_TYPE_UNMARSHALL(ULONGLONG); + TRACE("value: %s\n", wine_dbgstr_longlong(**(ULONGLONG **)ppMemory)); + break; + case RPC_FC_ENUM16: + ALIGN_POINTER(pStubMsg->Buffer, sizeof(USHORT)); + if (fMustAlloc || !*ppMemory) + *ppMemory = NdrAllocate(pStubMsg, sizeof(UINT)); + TRACE("*ppMemory: %p\n", *ppMemory); + /* 16-bits on the wire, but int in memory */ + **(UINT **)ppMemory = *(USHORT *)pStubMsg->Buffer; + pStubMsg->Buffer += sizeof(USHORT); + TRACE("value: 0x%08x\n", **(UINT **)ppMemory); + break; + default: + FIXME("Unhandled base type: 0x%02x\n", *pFormat); + } +#undef BASE_TYPE_UNMARSHALL + + /* FIXME: what is the correct return value? */ + + return NULL; +} + +/*********************************************************************** + * NdrBaseTypeBufferSize [internal] + */ +static void WINAPI NdrBaseTypeBufferSize( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + switch(*pFormat) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + pStubMsg->BufferLength += sizeof(UCHAR); + break; + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + case RPC_FC_ENUM16: + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(USHORT)); + pStubMsg->BufferLength += sizeof(USHORT); + break; + case RPC_FC_LONG: + case RPC_FC_ULONG: + case RPC_FC_ENUM32: + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(ULONG)); + pStubMsg->BufferLength += sizeof(ULONG); + break; + case RPC_FC_FLOAT: + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(float)); + pStubMsg->BufferLength += sizeof(float); + break; + case RPC_FC_DOUBLE: + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(double)); + pStubMsg->BufferLength += sizeof(double); + break; + case RPC_FC_HYPER: + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(ULONGLONG)); + pStubMsg->BufferLength += sizeof(ULONGLONG); + break; + case RPC_FC_ERROR_STATUS_T: + ALIGN_LENGTH(pStubMsg->BufferLength, sizeof(error_status_t)); + pStubMsg->BufferLength += sizeof(error_status_t); + break; + default: + FIXME("Unhandled base type: 0x%02x\n", *pFormat); + } +} + +/*********************************************************************** + * NdrBaseTypeMemorySize [internal] + */ +static ULONG WINAPI NdrBaseTypeMemorySize( + PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + switch(*pFormat) + { + case RPC_FC_BYTE: + case RPC_FC_CHAR: + case RPC_FC_SMALL: + case RPC_FC_USMALL: + pStubMsg->Buffer += sizeof(UCHAR); + pStubMsg->MemorySize += sizeof(UCHAR); + return sizeof(UCHAR); + case RPC_FC_WCHAR: + case RPC_FC_SHORT: + case RPC_FC_USHORT: + pStubMsg->Buffer += sizeof(USHORT); + pStubMsg->MemorySize += sizeof(USHORT); + return sizeof(USHORT); + case RPC_FC_LONG: + case RPC_FC_ULONG: + pStubMsg->Buffer += sizeof(ULONG); + pStubMsg->MemorySize += sizeof(ULONG); + return sizeof(ULONG); + case RPC_FC_FLOAT: + pStubMsg->Buffer += sizeof(float); + pStubMsg->MemorySize += sizeof(float); + return sizeof(float); + case RPC_FC_DOUBLE: + pStubMsg->Buffer += sizeof(double); + pStubMsg->MemorySize += sizeof(double); + return sizeof(double); + case RPC_FC_HYPER: + pStubMsg->Buffer += sizeof(ULONGLONG); + pStubMsg->MemorySize += sizeof(ULONGLONG); + return sizeof(ULONGLONG); + case RPC_FC_ERROR_STATUS_T: + pStubMsg->Buffer += sizeof(error_status_t); + pStubMsg->MemorySize += sizeof(error_status_t); + return sizeof(error_status_t); + case RPC_FC_ENUM16: + case RPC_FC_ENUM32: + pStubMsg->Buffer += sizeof(INT); + pStubMsg->MemorySize += sizeof(INT); + return sizeof(INT); + default: + FIXME("Unhandled base type: 0x%02x\n", *pFormat); + return 0; + } +} + +/*********************************************************************** + * NdrBaseTypeFree [internal] + */ +static void WINAPI NdrBaseTypeFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p pMemory %p type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + /* nothing to do */ +} + +/*********************************************************************** + * NdrContextHandleBufferSize [internal] + */ +static void WINAPI NdrContextHandleBufferSize( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (*pFormat != RPC_FC_BIND_CONTEXT) + { + ERR("invalid format type %x\n", *pFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + ALIGN_LENGTH(pStubMsg->BufferLength, 4); + pStubMsg->BufferLength += cbNDRContext; +} + +/*********************************************************************** + * NdrContextHandleMarshall [internal] + */ +static unsigned char *WINAPI NdrContextHandleMarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + TRACE("pStubMsg %p, pMemory %p, type 0x%02x\n", pStubMsg, pMemory, *pFormat); + + if (*pFormat != RPC_FC_BIND_CONTEXT) + { + ERR("invalid format type %x\n", *pFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + if (pFormat[1] & 0x80) + NdrClientContextMarshall(pStubMsg, *(NDR_CCONTEXT **)pMemory, FALSE); + else + NdrClientContextMarshall(pStubMsg, (NDR_CCONTEXT *)pMemory, FALSE); + + return NULL; +} + +/*********************************************************************** + * NdrContextHandleUnmarshall [internal] + */ +static unsigned char *WINAPI NdrContextHandleUnmarshall( + PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + if (*pFormat != RPC_FC_BIND_CONTEXT) + { + ERR("invalid format type %x\n", *pFormat); + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + **(NDR_CCONTEXT **)ppMemory = NULL; + NdrClientContextUnmarshall(pStubMsg, *(NDR_CCONTEXT **)ppMemory, pStubMsg->RpcMsg->Handle); + + return NULL; +} + +/*********************************************************************** + * NdrClientContextMarshall [RPCRT4.@] + */ +void WINAPI NdrClientContextMarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_CCONTEXT ContextHandle, + int fCheck) +{ + TRACE("(%p, %p, %d)\n", pStubMsg, ContextHandle, fCheck); + + ALIGN_POINTER(pStubMsg->Buffer, 4); + + /* FIXME: what does fCheck do? */ + NDRCContextMarshall(ContextHandle, + pStubMsg->Buffer); + + pStubMsg->Buffer += cbNDRContext; +} + +/*********************************************************************** + * NdrClientContextUnmarshall [RPCRT4.@] + */ +void WINAPI NdrClientContextUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_CCONTEXT * pContextHandle, + RPC_BINDING_HANDLE BindHandle) +{ + TRACE("(%p, %p, %p)\n", pStubMsg, pContextHandle, BindHandle); + + ALIGN_POINTER(pStubMsg->Buffer, 4); + + NDRCContextUnmarshall(pContextHandle, + BindHandle, + pStubMsg->Buffer, + pStubMsg->RpcMsg->DataRepresentation); + + pStubMsg->Buffer += cbNDRContext; +} + +void WINAPI NdrServerContextMarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_SCONTEXT ContextHandle, + NDR_RUNDOWN RundownRoutine ) +{ + FIXME("(%p, %p, %p): stub\n", pStubMsg, ContextHandle, RundownRoutine); +} + +NDR_SCONTEXT WINAPI NdrServerContextUnmarshall(PMIDL_STUB_MESSAGE pStubMsg) +{ + FIXME("(%p): stub\n", pStubMsg); + return NULL; +} + +void WINAPI NdrContextHandleSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char* pMemory, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p, %p): stub\n", pStubMsg, pMemory, pFormat); +} + +NDR_SCONTEXT WINAPI NdrContextHandleInitialize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p): stub\n", pStubMsg, pFormat); + return NULL; +} + +void WINAPI NdrServerContextNewMarshall(PMIDL_STUB_MESSAGE pStubMsg, + NDR_SCONTEXT ContextHandle, + NDR_RUNDOWN RundownRoutine, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p, %p, %p): stub\n", pStubMsg, ContextHandle, RundownRoutine, pFormat); +} + +NDR_SCONTEXT WINAPI NdrServerContextNewUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + FIXME("(%p, %p): stub\n", pStubMsg, pFormat); + return NULL; +} + +#define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e + +typedef struct ndr_context_handle +{ + DWORD attributes; + GUID uuid; +} ndr_context_handle; + +struct context_handle_entry +{ + struct list entry; + DWORD magic; + RPC_BINDING_HANDLE handle; + ndr_context_handle wire_data; +}; + +static struct list context_handle_list = LIST_INIT(context_handle_list); + +static CRITICAL_SECTION ndr_context_cs; +static CRITICAL_SECTION_DEBUG ndr_context_debug = +{ + 0, 0, &ndr_context_cs, + { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") } +}; +static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 }; + +static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext) +{ + struct context_handle_entry *che = (struct context_handle_entry*) CContext; + + if (che->magic != NDR_CONTEXT_HANDLE_MAGIC) + return NULL; + return che; +} + +static struct context_handle_entry *context_entry_from_guid(LPGUID uuid) +{ + struct context_handle_entry *che; + LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry) + if (IsEqualGUID(&che->wire_data.uuid, uuid)) + return che; + return NULL; +} + +RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext) +{ + struct context_handle_entry *che; + RPC_BINDING_HANDLE handle = NULL; + + TRACE("%p\n", CContext); + + EnterCriticalSection(&ndr_context_cs); + che = get_context_entry(CContext); + if (che) + handle = che->handle; + LeaveCriticalSection(&ndr_context_cs); + + if (!handle) + RpcRaiseException(ERROR_INVALID_HANDLE); + return handle; +} + +void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff) +{ + struct context_handle_entry *che; + + TRACE("%p %p\n", CContext, pBuff); + + if (CContext) + { + EnterCriticalSection(&ndr_context_cs); + che = get_context_entry(CContext); + memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle)); + LeaveCriticalSection(&ndr_context_cs); + } + else + { + ndr_context_handle *wire_data = (ndr_context_handle *)pBuff; + wire_data->attributes = 0; + wire_data->uuid = GUID_NULL; + } +} + +static UINT ndr_update_context_handle(NDR_CCONTEXT *CContext, + RPC_BINDING_HANDLE hBinding, + ndr_context_handle *chi) +{ + struct context_handle_entry *che = NULL; + + /* a null UUID means we should free the context handle */ + if (IsEqualGUID(&chi->uuid, &GUID_NULL)) + { + if (*CContext) + { + che = get_context_entry(*CContext); + if (!che) + return ERROR_INVALID_HANDLE; + list_remove(&che->entry); + RpcBindingFree(&che->handle); + HeapFree(GetProcessHeap(), 0, che); + che = NULL; + } + } + /* if there's no existing entry matching the GUID, allocate one */ + else if (!(che = context_entry_from_guid(&chi->uuid))) + { + che = HeapAlloc(GetProcessHeap(), 0, sizeof *che); + if (!che) + return ERROR_NOT_ENOUGH_MEMORY; + che->magic = NDR_CONTEXT_HANDLE_MAGIC; + RpcBindingCopy(hBinding, &che->handle); + list_add_tail(&context_handle_list, &che->entry); + memcpy(&che->wire_data, chi, sizeof *chi); + } + + *CContext = che; + + return ERROR_SUCCESS; +} + +/*********************************************************************** + * NDRCContextUnmarshall [RPCRT4.@] + */ +void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext, + RPC_BINDING_HANDLE hBinding, + void *pBuff, ULONG DataRepresentation) +{ + UINT r; + + TRACE("*%p=(%p) %p %p %08x\n", + CContext, *CContext, hBinding, pBuff, DataRepresentation); + + EnterCriticalSection(&ndr_context_cs); + r = ndr_update_context_handle(CContext, hBinding, pBuff); + LeaveCriticalSection(&ndr_context_cs); + if (r) + RpcRaiseException(r); +} + +/*********************************************************************** + * NDRSContextMarshall [RPCRT4.@] + */ +void WINAPI NDRSContextMarshall(NDR_SCONTEXT CContext, + void *pBuff, + NDR_RUNDOWN userRunDownIn) +{ + FIXME("(%p %p %p): stub\n", CContext, pBuff, userRunDownIn); +} + +/*********************************************************************** + * NDRSContextMarshallEx [RPCRT4.@] + */ +void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding, + NDR_SCONTEXT CContext, + void *pBuff, + NDR_RUNDOWN userRunDownIn) +{ + FIXME("(%p %p %p %p): stub\n", hBinding, CContext, pBuff, userRunDownIn); +} + +/*********************************************************************** + * NDRSContextMarshall2 [RPCRT4.@] + */ +void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding, + NDR_SCONTEXT CContext, + void *pBuff, + NDR_RUNDOWN userRunDownIn, + void *CtxGuard, ULONG Flags) +{ + FIXME("(%p %p %p %p %p %u): stub\n", + hBinding, CContext, pBuff, userRunDownIn, CtxGuard, Flags); +} + +/*********************************************************************** + * NDRSContextUnmarshall [RPCRT4.@] + */ +NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff, + ULONG DataRepresentation) +{ + FIXME("(%p %08x): stub\n", pBuff, DataRepresentation); + return NULL; +} + +/*********************************************************************** + * NDRSContextUnmarshallEx [RPCRT4.@] + */ +NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding, + void *pBuff, + ULONG DataRepresentation) +{ + FIXME("(%p %p %08x): stub\n", hBinding, pBuff, DataRepresentation); + return NULL; +} + +/*********************************************************************** + * NDRSContextUnmarshall2 [RPCRT4.@] + */ +NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding, + void *pBuff, + ULONG DataRepresentation, + void *CtxGuard, ULONG Flags) +{ + FIXME("(%p %p %08x %p %u): stub\n", + hBinding, pBuff, DataRepresentation, CtxGuard, Flags); + return NULL; +} diff --git a/reactos/dll/win32/rpcrt4_new/ndr_misc.h b/reactos/dll/win32/rpcrt4_new/ndr_misc.h new file mode 100644 index 00000000000..ebd70b8d826 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/ndr_misc.h @@ -0,0 +1,65 @@ +/* + * NDR definitions + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + */ + +#ifndef __WINE_NDR_MISC_H +#define __WINE_NDR_MISC_H + +#include + +#include "windef.h" +#include "winbase.h" +#include "rpc.h" +#include "rpcndr.h" + +struct IPSFactoryBuffer; + +PFORMAT_STRING ComputeConformanceOrVariance( + MIDL_STUB_MESSAGE *pStubMsg, unsigned char *pMemory, + PFORMAT_STRING pFormat, ULONG_PTR def, ULONG_PTR *pCount); + +static inline PFORMAT_STRING ComputeConformance(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, ULONG def) +{ + return ComputeConformanceOrVariance(pStubMsg, pMemory, pFormat, def, &pStubMsg->MaxCount); +} + +static inline PFORMAT_STRING ComputeVariance(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat, ULONG def) +{ + PFORMAT_STRING ret; + ULONG_PTR ActualCount = pStubMsg->ActualCount; + + pStubMsg->Offset = 0; + ret = ComputeConformanceOrVariance(pStubMsg, pMemory, pFormat, def, &ActualCount); + pStubMsg->ActualCount = (ULONG)ActualCount; + return ret; +} + +typedef unsigned char* (WINAPI *NDR_MARSHALL) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); +typedef unsigned char* (WINAPI *NDR_UNMARSHALL)(PMIDL_STUB_MESSAGE, unsigned char**,PFORMAT_STRING, unsigned char); +typedef void (WINAPI *NDR_BUFFERSIZE)(PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); +typedef ULONG (WINAPI *NDR_MEMORYSIZE)(PMIDL_STUB_MESSAGE, PFORMAT_STRING); +typedef void (WINAPI *NDR_FREE) (PMIDL_STUB_MESSAGE, unsigned char*, PFORMAT_STRING); + +extern const NDR_MARSHALL NdrMarshaller[]; +extern const NDR_UNMARSHALL NdrUnmarshaller[]; +extern const NDR_BUFFERSIZE NdrBufferSizer[]; +extern const NDR_MEMORYSIZE NdrMemorySizer[]; +extern const NDR_FREE NdrFreer[]; + +#endif /* __WINE_NDR_MISC_H */ diff --git a/reactos/dll/win32/rpcrt4_new/ndr_ole.c b/reactos/dll/win32/rpcrt4_new/ndr_ole.c new file mode 100644 index 00000000000..0a8c1f22797 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/ndr_ole.c @@ -0,0 +1,393 @@ +/* + * OLE32 callouts, COM interface marshalling + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + * + * TODO: + * - fix the wire-protocol to match MS/RPC + * - finish RpcStream_Vtbl + */ + +#include +#include +#include + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" + +#include "ndr_misc.h" +#include "rpcndr.h" +#include "rpcproxy.h" +#include "wine/rpcfc.h" +#include "cpsf.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +static HMODULE hOLE; + +static HRESULT (WINAPI *COM_GetMarshalSizeMax)(ULONG *,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); +static HRESULT (WINAPI *COM_MarshalInterface)(LPSTREAM,REFIID,LPUNKNOWN,DWORD,LPVOID,DWORD); +static HRESULT (WINAPI *COM_UnmarshalInterface)(LPSTREAM,REFIID,LPVOID*); +static HRESULT (WINAPI *COM_ReleaseMarshalData)(LPSTREAM); +static HRESULT (WINAPI *COM_GetClassObject)(REFCLSID,DWORD,COSERVERINFO *,REFIID,LPVOID *); +static HRESULT (WINAPI *COM_GetPSClsid)(REFIID,CLSID *); +static LPVOID (WINAPI *COM_MemAlloc)(ULONG); +static void (WINAPI *COM_MemFree)(LPVOID); + +static HMODULE LoadCOM(void) +{ + if (hOLE) return hOLE; + hOLE = LoadLibraryA("OLE32.DLL"); + if (!hOLE) return 0; + COM_GetMarshalSizeMax = (LPVOID)GetProcAddress(hOLE, "CoGetMarshalSizeMax"); + COM_MarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoMarshalInterface"); + COM_UnmarshalInterface = (LPVOID)GetProcAddress(hOLE, "CoUnmarshalInterface"); + COM_ReleaseMarshalData = (LPVOID)GetProcAddress(hOLE, "CoReleaseMarshalData"); + COM_GetClassObject = (LPVOID)GetProcAddress(hOLE, "CoGetClassObject"); + COM_GetPSClsid = (LPVOID)GetProcAddress(hOLE, "CoGetPSClsid"); + COM_MemAlloc = (LPVOID)GetProcAddress(hOLE, "CoTaskMemAlloc"); + COM_MemFree = (LPVOID)GetProcAddress(hOLE, "CoTaskMemFree"); + return hOLE; +} + +/* CoMarshalInterface/CoUnmarshalInterface works on streams, + * so implement a simple stream on top of the RPC buffer + * (which also implements the MInterfacePointer structure) */ +typedef struct RpcStreamImpl +{ + const IStreamVtbl *lpVtbl; + DWORD RefCount; + PMIDL_STUB_MESSAGE pMsg; + LPDWORD size; + char *data; + DWORD pos; +} RpcStreamImpl; + +static HRESULT WINAPI RpcStream_QueryInterface(LPSTREAM iface, + REFIID riid, + LPVOID *obj) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_ISequentialStream, riid) || + IsEqualGUID(&IID_IStream, riid)) { + *obj = This; + This->RefCount++; + return S_OK; + } + return E_NOINTERFACE; +} + +static ULONG WINAPI RpcStream_AddRef(LPSTREAM iface) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + return ++(This->RefCount); +} + +static ULONG WINAPI RpcStream_Release(LPSTREAM iface) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + if (!--(This->RefCount)) { + TRACE("size=%d\n", *This->size); + This->pMsg->Buffer = (unsigned char*)This->data + *This->size; + HeapFree(GetProcessHeap(),0,This); + return 0; + } + return This->RefCount; +} + +static HRESULT WINAPI RpcStream_Read(LPSTREAM iface, + void *pv, + ULONG cb, + ULONG *pcbRead) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + HRESULT hr = S_OK; + if (This->pos + cb > *This->size) + { + cb = *This->size - This->pos; + hr = S_FALSE; + } + if (cb) { + memcpy(pv, This->data + This->pos, cb); + This->pos += cb; + } + if (pcbRead) *pcbRead = cb; + return hr; +} + +static HRESULT WINAPI RpcStream_Write(LPSTREAM iface, + const void *pv, + ULONG cb, + ULONG *pcbWritten) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + if (This->data + cb > (char *)This->pMsg->BufferEnd) + return STG_E_MEDIUMFULL; + memcpy(This->data + This->pos, pv, cb); + This->pos += cb; + if (This->pos > *This->size) *This->size = This->pos; + if (pcbWritten) *pcbWritten = cb; + return S_OK; +} + +static HRESULT WINAPI RpcStream_Seek(LPSTREAM iface, + LARGE_INTEGER move, + DWORD origin, + ULARGE_INTEGER *newPos) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + switch (origin) { + case STREAM_SEEK_SET: + This->pos = move.u.LowPart; + break; + case STREAM_SEEK_CUR: + This->pos = This->pos + move.u.LowPart; + break; + case STREAM_SEEK_END: + This->pos = *This->size + move.u.LowPart; + break; + default: + return STG_E_INVALIDFUNCTION; + } + if (newPos) { + newPos->u.LowPart = This->pos; + newPos->u.HighPart = 0; + } + return S_OK; +} + +static HRESULT WINAPI RpcStream_SetSize(LPSTREAM iface, + ULARGE_INTEGER newSize) +{ + RpcStreamImpl *This = (RpcStreamImpl *)iface; + *This->size = newSize.u.LowPart; + return S_OK; +} + +static const IStreamVtbl RpcStream_Vtbl = +{ + RpcStream_QueryInterface, + RpcStream_AddRef, + RpcStream_Release, + RpcStream_Read, + RpcStream_Write, + RpcStream_Seek, + RpcStream_SetSize, + NULL, /* CopyTo */ + NULL, /* Commit */ + NULL, /* Revert */ + NULL, /* LockRegion */ + NULL, /* UnlockRegion */ + NULL, /* Stat */ + NULL /* Clone */ +}; + +static LPSTREAM RpcStream_Create(PMIDL_STUB_MESSAGE pStubMsg, BOOL init) +{ + RpcStreamImpl *This; + This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(RpcStreamImpl)); + if (!This) return NULL; + This->lpVtbl = &RpcStream_Vtbl; + This->RefCount = 1; + This->pMsg = pStubMsg; + This->size = (LPDWORD)pStubMsg->Buffer; + This->data = (char*)(This->size + 1); + This->pos = 0; + if (init) *This->size = 0; + TRACE("init size=%d\n", *This->size); + return (LPSTREAM)This; +} + +static const IID* get_ip_iid(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) +{ + const IID *riid; + if (!pFormat) return &IID_IUnknown; + TRACE("format=%02x %02x\n", pFormat[0], pFormat[1]); + if (pFormat[0] != RPC_FC_IP) FIXME("format=%d\n", pFormat[0]); + if (pFormat[1] == RPC_FC_CONSTANT_IID) { + riid = (const IID *)&pFormat[2]; + } else { + ComputeConformance(pStubMsg, pMemory, pFormat+2, 0); + riid = (const IID *)pStubMsg->MaxCount; + } + if (!riid) riid = &IID_IUnknown; + TRACE("got %s\n", debugstr_guid(riid)); + return riid; +} + +/*********************************************************************** + * NdrInterfacePointerMarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrInterfacePointerMarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const IID *riid = get_ip_iid(pStubMsg, pMemory, pFormat); + LPSTREAM stream; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + pStubMsg->MaxCount = 0; + if (!LoadCOM()) return NULL; + if (pStubMsg->Buffer + sizeof(DWORD) <= (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength) { + stream = RpcStream_Create(pStubMsg, TRUE); + if (stream) { + if (pMemory) + hr = COM_MarshalInterface(stream, riid, (LPUNKNOWN)pMemory, + pStubMsg->dwDestContext, pStubMsg->pvDestContext, + MSHLFLAGS_NORMAL); + else + hr = S_OK; + + IStream_Release(stream); + if (FAILED(hr)) + RpcRaiseException(hr); + } + } + return NULL; +} + +/*********************************************************************** + * NdrInterfacePointerUnmarshall [RPCRT4.@] + */ +unsigned char * WINAPI NdrInterfacePointerUnmarshall(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char **ppMemory, + PFORMAT_STRING pFormat, + unsigned char fMustAlloc) +{ + LPSTREAM stream; + HRESULT hr; + + TRACE("(%p,%p,%p,%d)\n", pStubMsg, ppMemory, pFormat, fMustAlloc); + if (!LoadCOM()) return NULL; + *(LPVOID*)ppMemory = NULL; + if (pStubMsg->Buffer + sizeof(DWORD) < (unsigned char *)pStubMsg->RpcMsg->Buffer + pStubMsg->BufferLength) { + stream = RpcStream_Create(pStubMsg, FALSE); + if (!stream) RpcRaiseException(E_OUTOFMEMORY); + if (*((RpcStreamImpl *)stream)->size != 0) + hr = COM_UnmarshalInterface(stream, &IID_NULL, (LPVOID*)ppMemory); + else + hr = S_OK; + IStream_Release(stream); + if (FAILED(hr)) + RpcRaiseException(hr); + } + return NULL; +} + +/*********************************************************************** + * NdrInterfacePointerBufferSize [RPCRT4.@] + */ +void WINAPI NdrInterfacePointerBufferSize(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + const IID *riid = get_ip_iid(pStubMsg, pMemory, pFormat); + ULONG size = 0; + HRESULT hr; + + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (!LoadCOM()) return; + hr = COM_GetMarshalSizeMax(&size, riid, (LPUNKNOWN)pMemory, + pStubMsg->dwDestContext, pStubMsg->pvDestContext, + MSHLFLAGS_NORMAL); + TRACE("size=%d\n", size); + pStubMsg->BufferLength += sizeof(DWORD) + size; +} + +/*********************************************************************** + * NdrInterfacePointerMemorySize [RPCRT4.@] + */ +ULONG WINAPI NdrInterfacePointerMemorySize(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat) +{ + ULONG size; + + TRACE("(%p,%p)\n", pStubMsg, pFormat); + + size = *(ULONG *)pStubMsg->Buffer; + pStubMsg->Buffer += 4; + pStubMsg->MemorySize += 4; + + pStubMsg->Buffer += size; + + return pStubMsg->MemorySize; +} + +/*********************************************************************** + * NdrInterfacePointerFree [RPCRT4.@] + */ +void WINAPI NdrInterfacePointerFree(PMIDL_STUB_MESSAGE pStubMsg, + unsigned char *pMemory, + PFORMAT_STRING pFormat) +{ + LPUNKNOWN pUnk = (LPUNKNOWN)pMemory; + TRACE("(%p,%p,%p)\n", pStubMsg, pMemory, pFormat); + if (pUnk) IUnknown_Release(pUnk); +} + +/*********************************************************************** + * NdrOleAllocate [RPCRT4.@] + */ +void * WINAPI NdrOleAllocate(size_t Size) +{ + if (!LoadCOM()) return NULL; + return COM_MemAlloc(Size); +} + +/*********************************************************************** + * NdrOleFree [RPCRT4.@] + */ +void WINAPI NdrOleFree(void *NodeToFree) +{ + if (!LoadCOM()) return; + COM_MemFree(NodeToFree); +} + +/*********************************************************************** + * Helper function to create a stub. + * This probably looks very much like NdrpCreateStub. + */ +HRESULT create_stub(REFIID iid, IUnknown *pUnk, IRpcStubBuffer **ppstub) +{ + CLSID clsid; + IPSFactoryBuffer *psfac; + HRESULT r; + + if(!LoadCOM()) return E_FAIL; + + r = COM_GetPSClsid( iid, &clsid ); + if(FAILED(r)) return r; + + r = COM_GetClassObject( &clsid, CLSCTX_INPROC_SERVER, NULL, &IID_IPSFactoryBuffer, (void**)&psfac ); + if(FAILED(r)) return r; + + r = IPSFactoryBuffer_CreateStub(psfac, iid, pUnk, ppstub); + + IPSFactoryBuffer_Release(psfac); + return r; +} diff --git a/reactos/dll/win32/rpcrt4_new/ndr_stubless.c b/reactos/dll/win32/rpcrt4_new/ndr_stubless.c new file mode 100644 index 00000000000..9eb25effa97 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/ndr_stubless.c @@ -0,0 +1,1628 @@ +/* + * NDR -Oi,-Oif,-Oicf Interpreter + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2003-5 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 + * + * TODO: + * - Pipes + * - Some types of binding handles + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "objbase.h" +#include "rpc.h" +#include "rpcproxy.h" +#include "ndrtypes.h" + +#include "wine/debug.h" +#include "wine/rpcfc.h" + +#include "ndr_misc.h" +#include "cpsf.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +#define NDR_TABLE_MASK 127 + +static inline void call_buffer_sizer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) +{ + NDR_BUFFERSIZE m = NdrBufferSizer[pFormat[0] & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, pFormat); + else + { + FIXME("format type 0x%x not implemented\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static inline unsigned char *call_marshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) +{ + NDR_MARSHALL m = NdrMarshaller[pFormat[0] & NDR_TABLE_MASK]; + if (m) return m(pStubMsg, pMemory, pFormat); + else + { + FIXME("format type 0x%x not implemented\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + return NULL; + } +} + +static inline unsigned char *call_unmarshaller(PMIDL_STUB_MESSAGE pStubMsg, unsigned char **ppMemory, PFORMAT_STRING pFormat, unsigned char fMustAlloc) +{ + NDR_UNMARSHALL m = NdrUnmarshaller[pFormat[0] & NDR_TABLE_MASK]; + if (m) return m(pStubMsg, ppMemory, pFormat, fMustAlloc); + else + { + FIXME("format type 0x%x not implemented\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + return NULL; + } +} + +static inline void call_freer(PMIDL_STUB_MESSAGE pStubMsg, unsigned char *pMemory, PFORMAT_STRING pFormat) +{ + NDR_FREE m = NdrFreer[pFormat[0] & NDR_TABLE_MASK]; + if (m) m(pStubMsg, pMemory, pFormat); +} + +static inline unsigned long call_memory_sizer(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat) +{ + NDR_MEMORYSIZE m = NdrMemorySizer[pFormat[0] & NDR_TABLE_MASK]; + if (m) + { + unsigned char *saved_buffer = pStubMsg->Buffer; + unsigned long ret; + int saved_ignore_embedded_pointers = pStubMsg->IgnoreEmbeddedPointers; + pStubMsg->MemorySize = 0; + pStubMsg->IgnoreEmbeddedPointers = 1; + ret = m(pStubMsg, pFormat); + pStubMsg->IgnoreEmbeddedPointers = saved_ignore_embedded_pointers; + pStubMsg->Buffer = saved_buffer; + return ret; + } + else + { + FIXME("format type 0x%x not implemented\n", pFormat[0]); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + return 0; + } +} + +/* there can't be any alignment with the structures in this file */ +#include "pshpack1.h" + +#define STUBLESS_UNMARSHAL 1 +#define STUBLESS_CALLSERVER 2 +#define STUBLESS_CALCSIZE 3 +#define STUBLESS_GETBUFFER 4 +#define STUBLESS_MARSHAL 5 +#define STUBLESS_FREE 6 + +/* From http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/parameter_descriptors.asp */ +typedef struct _NDR_PROC_HEADER +{ + /* type of handle to use: + * RPC_FC_BIND_EXPLICIT = 0 - Explicit handle. + * Handle is passed as a parameter to the function. + * Indicates that explicit handle information follows the header, + * which actually describes the handle. + * RPC_FC_BIND_GENERIC = 31 - Implicit handle with custom binding routines + * (MIDL_STUB_DESC::IMPLICIT_HANDLE_INFO::pGenericBindingInfo) + * RPC_FC_BIND_PRIMITIVE = 32 - Implicit handle using handle_t created by + * calling application + * RPC_FC_AUTO_HANDLE = 33 - Automatic handle + * RPC_FC_CALLBACK_HANDLE = 34 - undocmented + */ + unsigned char handle_type; + + /* procedure flags: + * Oi_FULL_PTR_USED = 0x01 - A full pointer can have the value NULL and can + * change during the call from NULL to non-NULL and supports aliasing + * and cycles. Indicates that the NdrFullPointerXlatInit function + * should be called. + * Oi_RPCSS_ALLOC_USED = 0x02 - Use RpcSS allocate/free routines instead of + * normal allocate/free routines + * Oi_OBJECT_PROC = 0x04 - Indicates a procedure that is part of an OLE + * interface, rather than a DCE RPC interface. + * Oi_HAS_RPCFLAGS = 0x08 - Indicates that the rpc_flags element is + * present in the header. + * Oi_HAS_COMM_OR_FAULT = 0x20 - If Oi_OBJECT_PROC not present only then + * indicates that the procedure has the comm_status or fault_status + * MIDL attribute. + * Oi_OBJ_USE_V2_INTERPRETER = 0x20 - If Oi_OBJECT_PROC present only + * then indicates that the format string is in -Oif or -Oicf format + * Oi_USE_NEW_INIT_ROUTINES = 0x40 - Use NdrXInitializeNew instead of + * NdrXInitialize? + */ + unsigned char Oi_flags; + + /* the zero-based index of the procedure */ + unsigned short proc_num; + + /* total size of all parameters on the stack, including any "this" + * pointer and/or return value */ + unsigned short stack_size; +} NDR_PROC_HEADER; + +/* same as above struct except additional element rpc_flags */ +typedef struct _NDR_PROC_HEADER_RPC +{ + unsigned char handle_type; + unsigned char Oi_flags; + + /* + * RPCF_Idempotent = 0x0001 - [idempotent] MIDL attribute + * RPCF_Broadcast = 0x0002 - [broadcast] MIDL attribute + * RPCF_Maybe = 0x0004 - [maybe] MIDL attribute + * Reserved = 0x0008 - 0x0080 + * RPCF_Message = 0x0100 - [message] MIDL attribute + * Reserved = 0x0200 - 0x1000 + * RPCF_InputSynchronous = 0x2000 - unknown + * RPCF_Asynchronous = 0x4000 - [async] MIDL attribute + * Reserved = 0x8000 + */ + unsigned long rpc_flags; + unsigned short proc_num; + unsigned short stack_size; + +} NDR_PROC_HEADER_RPC; + +typedef struct _NDR_PROC_PARTIAL_OIF_HEADER +{ + /* the pre-computed client buffer size so that interpreter can skip all + * or some (if the flag RPC_FC_PROC_OI2F_CLTMUSTSIZE is specified) of the + * sizing pass */ + unsigned short constant_client_buffer_size; + + /* the pre-computed server buffer size so that interpreter can skip all + * or some (if the flag RPC_FC_PROC_OI2F_SRVMUSTSIZE is specified) of the + * sizing pass */ + unsigned short constant_server_buffer_size; + + INTERPRETER_OPT_FLAGS Oi2Flags; + + /* number of params */ + unsigned char number_of_params; +} NDR_PROC_PARTIAL_OIF_HEADER; + +typedef struct _NDR_PARAM_OI_BASETYPE +{ + /* parameter direction. One of: + * FC_IN_PARAM_BASETYPE = 0x4e - an in param + * FC_RETURN_PARAM_BASETYPE = 0x53 - a return param + */ + unsigned char param_direction; + + /* One of: FC_BYTE,FC_CHAR,FC_SMALL,FC_USMALL,FC_WCHAR,FC_SHORT,FC_USHORT, + * FC_LONG,FC_ULONG,FC_FLOAT,FC_HYPER,FC_DOUBLE,FC_ENUM16,FC_ENUM32, + * FC_ERROR_STATUS_T,FC_INT3264,FC_UINT3264 */ + unsigned char type_format_char; +} NDR_PARAM_OI_BASETYPE; + +typedef struct _NDR_PARAM_OI_OTHER +{ + /* One of: + * FC_IN_PARAM = 0x4d - An in param + * FC_IN_OUT_PARAM = 0x50 - An in/out param + * FC_OUT_PARAM = 0x51 - An out param + * FC_RETURN_PARAM = 0x52 - A return value + * FC_IN_PARAM_NO_FREE_INST = 0x4f - A param for which no freeing is done + */ + unsigned char param_direction; + + /* Size of param on stack in NUMBERS OF INTS */ + unsigned char stack_size; + + /* offset in the type format string table */ + unsigned short type_offset; +} NDR_PARAM_OI_OTHER; + +typedef struct _NDR_PARAM_OIF_BASETYPE +{ + PARAM_ATTRIBUTES param_attributes; + + /* the offset on the calling stack where the parameter is located */ + unsigned short stack_offset; + + /* see NDR_PARAM_OI_BASETYPE::type_format_char */ + unsigned char type_format_char; + + /* always FC_PAD */ + unsigned char unused; +} NDR_PARAM_OIF_BASETYPE; + +typedef struct _NDR_PARAM_OIF_OTHER +{ + PARAM_ATTRIBUTES param_attributes; + + /* see NDR_PARAM_OIF_BASETYPE::stack_offset */ + unsigned short stack_offset; + + /* offset into the provided type format string where the type for this + * parameter starts */ + unsigned short type_offset; +} NDR_PARAM_OIF_OTHER; + +/* explicit handle description for FC_BIND_PRIMITIVE type */ +typedef struct _NDR_EHD_PRIMITIVE +{ + /* FC_BIND_PRIMITIVE */ + unsigned char handle_type; + + /* is the handle passed in via a pointer? */ + unsigned char flag; + + /* offset from the beginning of the stack to the handle in bytes */ + unsigned short offset; +} NDR_EHD_PRIMITIVE; + +/* explicit handle description for FC_BIND_GENERIC type */ +typedef struct _NDR_EHD_GENERIC +{ + /* FC_BIND_GENERIC */ + unsigned char handle_type; + + /* upper 4bits is a flag indicating whether the handle is passed in + * via a pointer. lower 4bits is the size of the user defined generic + * handle type. the size must be less than or equal to the machine + * register size */ + unsigned char flag_and_size; + + /* offset from the beginning of the stack to the handle in bytes */ + unsigned short offset; + + /* the index into the aGenericBindingRoutinesPairs field of MIDL_STUB_DESC + * giving the bind and unbind routines for the handle */ + unsigned char binding_routine_pair_index; + + /* FC_PAD */ + unsigned char unused; +} NDR_EHD_GENERIC; + +/* explicit handle description for FC_BIND_CONTEXT type */ +typedef struct _NDR_EHD_CONTEXT +{ + /* FC_BIND_CONTEXT */ + unsigned char handle_type; + + /* Any of the following flags: + * NDR_CONTEXT_HANDLE_CANNOT_BE_NULL = 0x01 + * NDR_CONTEXT_HANDLE_SERIALIZE = 0x02 + * NDR_CONTEXT_HANDLE_NO_SERIALIZE = 0x04 + * NDR_STRICT_CONTEXT_HANDLE = 0x08 + * HANDLE_PARAM_IS_OUT = 0x20 + * HANDLE_PARAM_IS_RETURN = 0x21 + * HANDLE_PARAM_IS_IN = 0x40 + * HANDLE_PARAM_IS_VIA_PTR = 0x80 + */ + unsigned char flags; + + /* offset from the beginning of the stack to the handle in bytes */ + unsigned short offset; + + /* zero-based index on rundown routine in apfnNdrRundownRoutines field + * of MIDL_STUB_DESC */ + unsigned char context_rundown_routine_index; + + /* varies depending on NDR version used. + * V1: zero-based index into parameters + * V2: zero-based index into handles that are parameters */ + unsigned char param_num; +} NDR_EHD_CONTEXT; + +#include "poppack.h" + +void WINAPI NdrRpcSmSetClientToOsf(PMIDL_STUB_MESSAGE pMessage) +{ +#if 0 /* these functions are not defined yet */ + pMessage->pfnAllocate = NdrRpcSmClientAllocate; + pMessage->pfnFree = NdrRpcSmClientFree; +#endif +} + +static void WINAPI dump_RPC_FC_PROC_PF(PARAM_ATTRIBUTES param_attributes) +{ + if (param_attributes.MustSize) TRACE(" MustSize"); + if (param_attributes.MustFree) TRACE(" MustFree"); + if (param_attributes.IsPipe) TRACE(" IsPipe"); + if (param_attributes.IsIn) TRACE(" IsIn"); + if (param_attributes.IsOut) TRACE(" IsOut"); + if (param_attributes.IsReturn) TRACE(" IsReturn"); + if (param_attributes.IsBasetype) TRACE(" IsBasetype"); + if (param_attributes.IsByValue) TRACE(" IsByValue"); + if (param_attributes.IsSimpleRef) TRACE(" IsSimpleRef"); + if (param_attributes.IsDontCallFreeInst) TRACE(" IsDontCallFreeInst"); + if (param_attributes.SaveForAsyncFinish) TRACE(" SaveForAsyncFinish"); + if (param_attributes.ServerAllocSize) TRACE(" ServerAllocSize = %d", param_attributes.ServerAllocSize * 8); +} + +static void WINAPI dump_INTERPRETER_OPT_FLAGS(INTERPRETER_OPT_FLAGS Oi2Flags) +{ + if (Oi2Flags.ServerMustSize) TRACE(" ServerMustSize"); + if (Oi2Flags.ClientMustSize) TRACE(" ClientMustSize"); + if (Oi2Flags.HasReturn) TRACE(" HasReturn"); + if (Oi2Flags.HasPipes) TRACE(" HasPipes"); + if (Oi2Flags.Unused) TRACE(" Unused"); + if (Oi2Flags.HasAsyncUuid) TRACE(" HasAsyncUuid"); + if (Oi2Flags.HasExtensions) TRACE(" HasExtensions"); + if (Oi2Flags.HasAsyncHandle) TRACE(" HasAsyncHandle"); + TRACE("\n"); +} + +#define ARG_FROM_OFFSET(stubMsg, offset) ((stubMsg).StackTop + (offset)) + +static PFORMAT_STRING client_get_handle( + PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader, + PFORMAT_STRING pFormat, handle_t *phBinding) +{ + /* binding */ + switch (pProcHeader->handle_type) + { + /* explicit binding: parse additional section */ + case RPC_FC_BIND_EXPLICIT: + switch (*pFormat) /* handle_type */ + { + case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */ + { + const NDR_EHD_PRIMITIVE *pDesc = (const NDR_EHD_PRIMITIVE *)pFormat; + + TRACE("Explicit primitive handle @ %d\n", pDesc->offset); + + if (pDesc->flag) /* pointer to binding */ + *phBinding = **(handle_t **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + else + *phBinding = *(handle_t *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + return pFormat + sizeof(NDR_EHD_PRIMITIVE); + } + case RPC_FC_BIND_GENERIC: /* explicit generic */ + { + const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat; + void *pObject = NULL; + void *pArg; + const GENERIC_BINDING_ROUTINE_PAIR *pGenPair; + + TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index); + + if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR) + pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + else + pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf); + pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index]; + *phBinding = pGenPair->pfnBind(pObject); + return pFormat + sizeof(NDR_EHD_GENERIC); + } + case RPC_FC_BIND_CONTEXT: /* explicit context */ + { + const NDR_EHD_CONTEXT *pDesc = (const NDR_EHD_CONTEXT *)pFormat; + NDR_CCONTEXT context_handle; + TRACE("Explicit bind context\n"); + if (pDesc->flags & HANDLE_PARAM_IS_VIA_PTR) + { + TRACE("\tHANDLE_PARAM_IS_VIA_PTR\n"); + context_handle = **(NDR_CCONTEXT **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + } + else + context_handle = *(NDR_CCONTEXT *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + if ((pDesc->flags & NDR_CONTEXT_HANDLE_CANNOT_BE_NULL) && + !context_handle) + { + ERR("null context handle isn't allowed\n"); + RpcRaiseException(RPC_X_SS_IN_NULL_CONTEXT); + return NULL; + } + *phBinding = NDRCContextBinding(context_handle); + /* FIXME: should we store this structure in stubMsg.pContext? */ + return pFormat + sizeof(NDR_EHD_CONTEXT); + } + default: + ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + break; + case RPC_FC_BIND_GENERIC: /* implicit generic */ + FIXME("RPC_FC_BIND_GENERIC\n"); + RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */ + break; + case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */ + TRACE("Implicit primitive handle\n"); + *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pPrimitiveHandle; + break; + case RPC_FC_CALLBACK_HANDLE: /* implicit callback */ + FIXME("RPC_FC_CALLBACK_HANDLE\n"); + break; + case RPC_FC_AUTO_HANDLE: /* implicit auto handle */ + /* strictly speaking, it isn't necessary to set hBinding here + * since it isn't actually used (hence the automatic in its name), + * but then why does MIDL generate a valid entry in the + * MIDL_STUB_DESC for it? */ + TRACE("Implicit auto handle\n"); + *phBinding = *pStubMsg->StubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle; + break; + default: + ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + return pFormat; +} + +static void client_free_handle( + PMIDL_STUB_MESSAGE pStubMsg, const NDR_PROC_HEADER *pProcHeader, + PFORMAT_STRING pFormat, handle_t hBinding) +{ + /* binding */ + switch (pProcHeader->handle_type) + { + /* explicit binding: parse additional section */ + case RPC_FC_BIND_EXPLICIT: + switch (*pFormat) /* handle_type */ + { + case RPC_FC_BIND_GENERIC: /* explicit generic */ + { + const NDR_EHD_GENERIC *pDesc = (const NDR_EHD_GENERIC *)pFormat; + void *pObject = NULL; + void *pArg; + const GENERIC_BINDING_ROUTINE_PAIR *pGenPair; + + TRACE("Explicit generic binding handle #%d\n", pDesc->binding_routine_pair_index); + + if (pDesc->flag_and_size & HANDLE_PARAM_IS_VIA_PTR) + pArg = *(void **)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + else + pArg = (void *)ARG_FROM_OFFSET(*pStubMsg, pDesc->offset); + memcpy(&pObject, pArg, pDesc->flag_and_size & 0xf); + pGenPair = &pStubMsg->StubDesc->aGenericBindingRoutinePairs[pDesc->binding_routine_pair_index]; + pGenPair->pfnUnbind(pObject, hBinding); + break; + } + case RPC_FC_BIND_CONTEXT: /* explicit context */ + case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */ + break; + default: + ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + break; + case RPC_FC_BIND_GENERIC: /* implicit generic */ + FIXME("RPC_FC_BIND_GENERIC\n"); + RpcRaiseException(RPC_X_BAD_STUB_DATA); /* FIXME: remove when implemented */ + break; + case RPC_FC_CALLBACK_HANDLE: /* implicit callback */ + case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */ + case RPC_FC_AUTO_HANDLE: /* implicit auto handle */ + break; + default: + ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } +} + +static void client_do_args(PMIDL_STUB_MESSAGE pStubMsg, PFORMAT_STRING pFormat, + int phase, unsigned short number_of_params, unsigned char *pRetVal) +{ + /* current format string offset */ + int current_offset = 0; + /* current stack offset */ + unsigned short current_stack_offset = 0; + /* counter */ + unsigned short i; + + for (i = 0; i < number_of_params; i++) + { + const NDR_PARAM_OIF_BASETYPE *pParam = + (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset]; + unsigned char * pArg; + + current_stack_offset = pParam->stack_offset; + pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset); + + TRACE("param[%d]: new format\n", i); + TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n"); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset); + TRACE("\tmemory addr (before): %p\n", pArg); + + if (pParam->param_attributes.IsBasetype) + { + const unsigned char * pTypeFormat = + &pParam->type_format_char; + + if (pParam->param_attributes.IsSimpleRef) + pArg = *(unsigned char **)pArg; + + TRACE("\tbase type: 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_attributes.IsIn) + call_buffer_sizer(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_MARSHAL: + if (pParam->param_attributes.IsIn) + call_marshaller(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_UNMARSHAL: + if (pParam->param_attributes.IsOut) + { + if (pParam->param_attributes.IsReturn) + call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0); + else + call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0); + TRACE("pRetVal = %p\n", pRetVal); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_offset += sizeof(NDR_PARAM_OIF_BASETYPE); + } + else + { + const NDR_PARAM_OIF_OTHER *pParamOther = + (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset]; + + const unsigned char * pTypeFormat = + &(pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]); + + /* if a simple ref pointer then we have to do the + * check for the pointer being non-NULL. */ + if (pParam->param_attributes.IsSimpleRef) + { + if (!*(unsigned char **)pArg) + RpcRaiseException(RPC_X_NULL_REF_POINTER); + } + + TRACE("\tcomplex type: 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_attributes.IsIn) + { + if (pParam->param_attributes.IsByValue) + call_buffer_sizer(pStubMsg, pArg, pTypeFormat); + else + call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + } + break; + case PROXY_MARSHAL: + if (pParam->param_attributes.IsIn) + { + if (pParam->param_attributes.IsByValue) + call_marshaller(pStubMsg, pArg, pTypeFormat); + else + call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + } + break; + case PROXY_UNMARSHAL: + if (pParam->param_attributes.IsOut) + { + if (pParam->param_attributes.IsReturn) + call_unmarshaller(pStubMsg, &pRetVal, pTypeFormat, 0); + else if (pParam->param_attributes.IsByValue) + call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0); + else + call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_offset += sizeof(NDR_PARAM_OIF_OTHER); + } + TRACE("\tmemory addr (after): %p\n", pArg); + } +} + +static void client_do_args_old_format(PMIDL_STUB_MESSAGE pStubMsg, + PFORMAT_STRING pFormat, int phase, unsigned short stack_size, + unsigned char *pRetVal, BOOL object_proc) +{ + /* current format string offset */ + int current_offset = 0; + /* current stack offset */ + unsigned short current_stack_offset = 0; + /* counter */ + unsigned short i; + + /* NOTE: V1 style format does't terminate on the number_of_params + * condition as it doesn't have this attribute. Instead it + * terminates when the stack size given in the header is exceeded. + */ + for (i = 0; TRUE; i++) + { + const NDR_PARAM_OI_BASETYPE *pParam = + (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset]; + /* note: current_stack_offset starts after the This pointer + * if present, so adjust this */ + unsigned short current_stack_offset_adjusted = current_stack_offset + + (object_proc ? sizeof(void *) : 0); + unsigned char * pArg = ARG_FROM_OFFSET(*pStubMsg, current_stack_offset_adjusted); + + /* no more parameters; exit loop */ + if (current_stack_offset_adjusted >= stack_size) + break; + + TRACE("param[%d]: old format\n", i); + TRACE("\tparam_direction: 0x%x\n", pParam->param_direction); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted); + TRACE("\tmemory addr (before): %p\n", pArg); + + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE || + pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + { + const unsigned char * pTypeFormat = + &pParam->type_format_char; + + TRACE("\tbase type 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) + call_buffer_sizer(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_MARSHAL: + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) + call_marshaller(pStubMsg, pArg, pTypeFormat); + break; + case PROXY_UNMARSHAL: + if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + { + if (pParam->param_direction & RPC_FC_RETURN_PARAM) + call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0); + else + call_unmarshaller(pStubMsg, &pArg, pTypeFormat, 0); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_stack_offset += call_memory_sizer(pStubMsg, pTypeFormat); + current_offset += sizeof(NDR_PARAM_OI_BASETYPE); + } + else + { + const NDR_PARAM_OI_OTHER *pParamOther = + (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset]; + + const unsigned char *pTypeFormat = + &pStubMsg->StubDesc->pFormatTypes[pParamOther->type_offset]; + + TRACE("\tcomplex type 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case PROXY_CALCSIZE: + if (pParam->param_direction == RPC_FC_IN_PARAM || + pParam->param_direction & RPC_FC_IN_OUT_PARAM) + call_buffer_sizer(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + break; + case PROXY_MARSHAL: + if (pParam->param_direction == RPC_FC_IN_PARAM || + pParam->param_direction & RPC_FC_IN_OUT_PARAM) + call_marshaller(pStubMsg, *(unsigned char **)pArg, pTypeFormat); + break; + case PROXY_UNMARSHAL: + if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_OUT_PARAM) + call_unmarshaller(pStubMsg, (unsigned char **)pArg, pTypeFormat, 0); + else if (pParam->param_direction == RPC_FC_RETURN_PARAM) + call_unmarshaller(pStubMsg, (unsigned char **)pRetVal, pTypeFormat, 0); + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_stack_offset += pParamOther->stack_size * sizeof(INT); + current_offset += sizeof(NDR_PARAM_OI_OTHER); + } + TRACE("\tmemory addr (after): %p\n", pArg); + } +} + +/* the return type should be CLIENT_CALL_RETURN, but this is incompatible + * with the way gcc returns structures. "void *" should be the largest type + * that MIDL should allow you to return anyway */ +LONG_PTR WINAPIV NdrClientCall2(PMIDL_STUB_DESC pStubDesc, PFORMAT_STRING pFormat, ...) +{ + /* pointer to start of stack where arguments start */ + RPC_MESSAGE rpcMsg; + MIDL_STUB_MESSAGE stubMsg; + handle_t hBinding = NULL; + /* procedure number */ + unsigned short procedure_number; + /* size of stack */ + unsigned short stack_size; + /* number of parameters. optional for client to give it to us */ + unsigned char number_of_params = ~0; + /* cache of Oif_flags from v2 procedure header */ + INTERPRETER_OPT_FLAGS Oif_flags = { 0 }; + /* cache of extension flags from NDR_PROC_HEADER_EXTS */ + INTERPRETER_OPT_FLAGS2 ext_flags = { 0 }; + /* the type of pass we are currently doing */ + int phase; + /* header for procedure string */ + const NDR_PROC_HEADER * pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0]; + /* -Oif or -Oicf generated format */ + BOOL bV2Format = FALSE; + /* the value to return to the client from the remote procedure */ + LONG_PTR RetVal = 0; + /* the pointer to the object when in OLE mode */ + void * This = NULL; + PFORMAT_STRING pHandleFormat; + + TRACE("pStubDesc %p, pFormat %p, ...\n", 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); + } + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) + { + const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0]; + stack_size = pProcHeader->stack_size; + procedure_number = pProcHeader->proc_num; + pFormat += sizeof(NDR_PROC_HEADER_RPC); + } + else + { + stack_size = pProcHeader->stack_size; + procedure_number = pProcHeader->proc_num; + pFormat += sizeof(NDR_PROC_HEADER); + } + TRACE("stack size: 0x%x\n", stack_size); + TRACE("proc num: %d\n", procedure_number); + + /* create the full pointer translation tables, if requested */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) + stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_CLIENT); + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + { + /* object is always the first argument */ + This = **(void *const **)(&pFormat+1); + NdrProxyInitialize(This, &rpcMsg, &stubMsg, pStubDesc, procedure_number); + } + else + NdrClientInitializeNew(&rpcMsg, &stubMsg, pStubDesc, procedure_number); + + TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags); + TRACE("MIDL stub version = 0x%x\n", pStubDesc->MIDLVersion); + + /* needed for conformance of top-level objects */ +#ifdef __i386__ + stubMsg.StackTop = *(unsigned char **)(&pFormat+1); +#else +# warning Stack not retrieved for your CPU architecture +#endif + + pHandleFormat = pFormat; + + /* we only need a handle if this isn't an object method */ + if (!(pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)) + { + pFormat = client_get_handle(&stubMsg, pProcHeader, pHandleFormat, &hBinding); + if (!pFormat) return 0; + } + + bV2Format = (pStubDesc->Version >= 0x20000); + + if (bV2Format) + { + const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = + (const NDR_PROC_PARTIAL_OIF_HEADER *)pFormat; + + Oif_flags = pOIFHeader->Oi2Flags; + number_of_params = pOIFHeader->number_of_params; + + pFormat += sizeof(NDR_PROC_PARTIAL_OIF_HEADER); + } + + TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags); + + if (Oif_flags.HasExtensions) + { + const NDR_PROC_HEADER_EXTS *pExtensions = + (const NDR_PROC_HEADER_EXTS *)pFormat; + ext_flags = pExtensions->Flags2; + pFormat += pExtensions->Size; + } + + stubMsg.BufferLength = 0; + + /* store the RPC flags away */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) + rpcMsg.RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags; + + /* use alternate memory allocation routines */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC) + NdrRpcSmSetClientToOsf(&stubMsg); + + if (Oif_flags.HasPipes) + { + FIXME("pipes not supported yet\n"); + RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */ + /* init pipes package */ + /* NdrPipesInitialize(...) */ + } + if (ext_flags.HasNewCorrDesc) + { + /* initialize extra correlation package */ + FIXME("new correlation description not implemented\n"); + stubMsg.fHasNewCorrDesc = TRUE; + } + + /* order of phases: + * 1. PROXY_CALCSIZE - calculate the buffer size + * 2. PROXY_GETBUFFER - allocate the buffer + * 3. PROXY_MARHSAL - marshal [in] params into the buffer + * 4. PROXY_SENDRECEIVE - send/receive buffer + * 5. PROXY_UNMARHSAL - unmarshal [out] params from buffer + */ + for (phase = PROXY_CALCSIZE; phase <= PROXY_UNMARSHAL; phase++) + { + TRACE("phase = %d\n", phase); + switch (phase) + { + case PROXY_GETBUFFER: + /* allocate the buffer */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + NdrProxyGetBuffer(This, &stubMsg); + else if (Oif_flags.HasPipes) + /* NdrGetPipeBuffer(...) */ + FIXME("pipes not supported yet\n"); + else + { + if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE) +#if 0 + NdrNsGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding); +#else + FIXME("using auto handle - call NdrNsGetBuffer when it gets implemented\n"); +#endif + else + NdrGetBuffer(&stubMsg, stubMsg.BufferLength, hBinding); + } + break; + case PROXY_SENDRECEIVE: + /* send the [in] params and receive the [out] and [retval] + * params */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + NdrProxySendReceive(This, &stubMsg); + else if (Oif_flags.HasPipes) + /* NdrPipesSendReceive(...) */ + FIXME("pipes not supported yet\n"); + else + { + if (pProcHeader->handle_type == RPC_FC_AUTO_HANDLE) +#if 0 + NdrNsSendReceive(&stubMsg, stubMsg.Buffer, pStubDesc->IMPLICIT_HANDLE_INFO.pAutoHandle); +#else + FIXME("using auto handle - call NdrNsSendReceive when it gets implemented\n"); +#endif + else + NdrSendReceive(&stubMsg, stubMsg.Buffer); + } + + /* convert strings, floating point values and endianess into our + * preferred format */ + if ((rpcMsg.DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION) + NdrConvert(&stubMsg, pFormat); + + break; + case PROXY_CALCSIZE: + case PROXY_MARSHAL: + case PROXY_UNMARSHAL: + if (bV2Format) + client_do_args(&stubMsg, pFormat, phase, number_of_params, + (unsigned char *)&RetVal); + else + client_do_args_old_format(&stubMsg, pFormat, phase, stack_size, + (unsigned char *)&RetVal, + (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT)); + break; + default: + ERR("shouldn't reach here. phase %d\n", phase); + break; + } + } + + if (ext_flags.HasNewCorrDesc) + { + /* free extra correlation package */ + /* NdrCorrelationFree(&stubMsg); */ + } + + if (Oif_flags.HasPipes) + { + /* NdrPipesDone(...) */ + } + + /* free the full pointer translation tables */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) + NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables); + + /* free marshalling buffer */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + NdrProxyFreeBuffer(This, &stubMsg); + else + { + NdrFreeBuffer(&stubMsg); + client_free_handle(&stubMsg, pProcHeader, pHandleFormat, hBinding); + } + + TRACE("RetVal = 0x%lx\n", RetVal); + + return RetVal; +} + +/* calls a function with the specificed arguments, restoring the stack + * properly afterwards as we don't know the calling convention of the + * function */ +#if defined __i386__ && defined _MSC_VER +__declspec(naked) LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size) +{ + __asm + { + push ebp + push edi ; Save registers + push esi + mov ebp, esp + mov eax, [ebp+16] ; Get stack size + sub esp, eax ; Make room in stack for arguments + mov edi, esp + mov ecx, eax + mov esi, [ebp+12] + shr ecx, 2 + cld + rep movsd ; Copy dword blocks + call [ebp+8] ; Call function + lea esp, [ebp-8] ; Restore stack + pop esi ; Restore registers + pop edi + pop ebp + ret + } +} +#elif defined __i386__ && defined __GNUC__ +LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned int stack_size); +__ASM_GLOBAL_FUNC(call_server_func, + "pushl %ebp\n\t" + "movl %esp, %ebp\n\t" + "pushl %edi\n\t" /* Save registers */ + "pushl %esi\n\t" + "movl 16(%ebp), %eax\n\t" /* Get stack size */ + "subl %eax, %esp\n\t" /* Make room in stack for arguments */ + "andl $~15, %esp\n\t" /* Make sure stack has 16-byte alignment for Mac OS X */ + "movl %esp, %edi\n\t" + "movl %eax, %ecx\n\t" + "movl 12(%ebp), %esi\n\t" + "shrl $2, %ecx\n\t" /* divide by 4 */ + "cld\n\t" + "rep; movsl\n\t" /* Copy dword blocks */ + "call *8(%ebp)\n\t" /* Call function */ + "leal -8(%ebp), %esp\n\t" /* Restore stack */ + "popl %esi\n\t" /* Restore registers */ + "popl %edi\n\t" + "popl %ebp\n\t" + "ret\n" ) +#else +#warning call_server_func not implemented for your architecture +LONG_PTR __cdecl call_server_func(SERVER_ROUTINE func, unsigned char * args, unsigned short stack_size) +{ + FIXME("Not implemented for your architecture\n"); + return 0; +} +#endif + +static DWORD calc_arg_size(MIDL_STUB_MESSAGE *pStubMsg, PFORMAT_STRING pFormat) +{ + DWORD size; + switch(*pFormat) + { + case RPC_FC_STRUCT: + size = *(const WORD*)(pFormat + 2); + break; + case RPC_FC_CARRAY: + size = *(const WORD*)(pFormat + 2); + ComputeConformance(pStubMsg, NULL, pFormat + 4, 0); + size *= pStubMsg->MaxCount; + break; + case RPC_FC_SMFARRAY: + size = *(const WORD*)(pFormat + 2); + break; + case RPC_FC_LGFARRAY: + size = *(const DWORD*)(pFormat + 2); + break; + default: + FIXME("Unhandled type %02x\n", *pFormat); + /* fallthrough */ + case RPC_FC_RP: + size = sizeof(void *); + break; + } + return size; +} + +/* FIXME: need to free some stuff in here too */ +LONG WINAPI NdrStubCall2( + struct IRpcStubBuffer * pThis, + struct IRpcChannelBuffer * pChannel, + PRPC_MESSAGE pRpcMsg, + DWORD * pdwStubPhase) +{ + const MIDL_SERVER_INFO *pServerInfo; + const MIDL_STUB_DESC *pStubDesc; + PFORMAT_STRING pFormat; + MIDL_STUB_MESSAGE stubMsg; + /* pointer to start of stack to pass into stub implementation */ + unsigned char * args; + /* size of stack */ + unsigned short stack_size; + /* current stack offset */ + unsigned short current_stack_offset; + /* number of parameters. optional for client to give it to us */ + unsigned char number_of_params = ~0; + /* counter */ + unsigned short i; + /* cache of Oif_flags from v2 procedure header */ + INTERPRETER_OPT_FLAGS Oif_flags = { 0 }; + /* cache of extension flags from NDR_PROC_HEADER_EXTS */ + INTERPRETER_OPT_FLAGS2 ext_flags = { 0 }; + /* the type of pass we are currently doing */ + int phase; + /* header for procedure string */ + const NDR_PROC_HEADER *pProcHeader; + /* offset in format string for start of params */ + int parameter_start_offset; + /* current format string offset */ + int current_offset; + /* -Oif or -Oicf generated format */ + BOOL bV2Format = FALSE; + /* location to put retval into */ + LONG_PTR *retval_ptr = NULL; + + TRACE("pThis %p, pChannel %p, pRpcMsg %p, pdwStubPhase %p\n", pThis, pChannel, pRpcMsg, pdwStubPhase); + + if (pThis) + pServerInfo = CStdStubBuffer_GetServerInfo(pThis); + else + pServerInfo = ((RPC_SERVER_INTERFACE *)pRpcMsg->RpcInterfaceInformation)->InterpreterInfo; + + pStubDesc = pServerInfo->pStubDesc; + pFormat = pServerInfo->ProcString + pServerInfo->FmtStringOffset[pRpcMsg->ProcNum]; + pProcHeader = (const NDR_PROC_HEADER *)&pFormat[0]; + + /* 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); + } + + /* create the full pointer translation tables, if requested */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) + stubMsg.FullPtrXlatTables = NdrFullPointerXlatInit(0,XLAT_SERVER); + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) + { + const NDR_PROC_HEADER_RPC *pProcHeader = (const NDR_PROC_HEADER_RPC *)&pFormat[0]; + stack_size = pProcHeader->stack_size; + current_offset = sizeof(NDR_PROC_HEADER_RPC); + + } + else + { + stack_size = pProcHeader->stack_size; + current_offset = sizeof(NDR_PROC_HEADER); + } + + TRACE("Oi_flags = 0x%02x\n", pProcHeader->Oi_flags); + + /* binding */ + switch (pProcHeader->handle_type) + { + /* explicit binding: parse additional section */ + case RPC_FC_BIND_EXPLICIT: + switch (pFormat[current_offset]) /* handle_type */ + { + case RPC_FC_BIND_PRIMITIVE: /* explicit primitive */ + current_offset += sizeof(NDR_EHD_PRIMITIVE); + break; + case RPC_FC_BIND_GENERIC: /* explicit generic */ + current_offset += sizeof(NDR_EHD_GENERIC); + break; + case RPC_FC_BIND_CONTEXT: /* explicit context */ + current_offset += sizeof(NDR_EHD_CONTEXT); + break; + default: + ERR("bad explicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + break; + case RPC_FC_BIND_GENERIC: /* implicit generic */ + case RPC_FC_BIND_PRIMITIVE: /* implicit primitive */ + case RPC_FC_CALLBACK_HANDLE: /* implicit callback */ + case RPC_FC_AUTO_HANDLE: /* implicit auto handle */ + break; + default: + ERR("bad implicit binding handle type (0x%02x)\n", pProcHeader->handle_type); + RpcRaiseException(RPC_X_BAD_STUB_DATA); + } + + bV2Format = (pStubDesc->Version >= 0x20000); + + if (bV2Format) + { + const NDR_PROC_PARTIAL_OIF_HEADER *pOIFHeader = + (const NDR_PROC_PARTIAL_OIF_HEADER *)&pFormat[current_offset]; + + Oif_flags = pOIFHeader->Oi2Flags; + number_of_params = pOIFHeader->number_of_params; + + current_offset += sizeof(NDR_PROC_PARTIAL_OIF_HEADER); + } + + TRACE("Oif_flags = "); dump_INTERPRETER_OPT_FLAGS(Oif_flags); + + if (Oif_flags.HasExtensions) + { + const NDR_PROC_HEADER_EXTS *pExtensions = + (const NDR_PROC_HEADER_EXTS *)&pFormat[current_offset]; + ext_flags = pExtensions->Flags2; + current_offset += pExtensions->Size; + } + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + NdrStubInitialize(pRpcMsg, &stubMsg, pStubDesc, pChannel); + else + NdrServerInitializeNew(pRpcMsg, &stubMsg, pStubDesc); + + /* store the RPC flags away */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCFLAGS) + pRpcMsg->RpcFlags = ((const NDR_PROC_HEADER_RPC *)pProcHeader)->rpc_flags; + + /* use alternate memory allocation routines */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_RPCSSALLOC) +#if 0 + NdrRpcSsEnableAllocate(&stubMsg); +#else + FIXME("Set RPCSS memory allocation routines\n"); +#endif + + if (Oif_flags.HasPipes) + { + FIXME("pipes not supported yet\n"); + RpcRaiseException(RPC_X_WRONG_STUB_VERSION); /* FIXME: remove when implemented */ + /* init pipes package */ + /* NdrPipesInitialize(...) */ + } + if (ext_flags.HasNewCorrDesc) + { + /* initialize extra correlation package */ + FIXME("new correlation description not implemented\n"); + stubMsg.fHasNewCorrDesc = TRUE; + } + + /* convert strings, floating point values and endianess into our + * preferred format */ + if ((pRpcMsg->DataRepresentation & 0x0000FFFFUL) != NDR_LOCAL_DATA_REPRESENTATION) + NdrConvert(&stubMsg, pFormat); + + parameter_start_offset = current_offset; + + TRACE("allocating memory for stack of size %x\n", stack_size); + + args = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, stack_size); + stubMsg.StackTop = args; /* used by conformance of top-level objects */ + + /* add the implicit This pointer as the first arg to the function if we + * are calling an object method */ + if (pThis) + *(void **)args = ((CStdStubBuffer *)pThis)->pvServerObject; + + /* order of phases: + * 1. STUBLESS_UNMARHSAL - unmarshal [in] params from buffer + * 2. STUBLESS_CALLSERVER - send/receive buffer + * 3. STUBLESS_CALCSIZE - get [out] buffer size + * 4. STUBLESS_GETBUFFER - allocate [out] buffer + * 5. STUBLESS_MARHSAL - marshal [out] params to buffer + */ + for (phase = STUBLESS_UNMARSHAL; phase <= STUBLESS_FREE; phase++) + { + TRACE("phase = %d\n", phase); + switch (phase) + { + case STUBLESS_CALLSERVER: + /* call the server function */ + if (pServerInfo->ThunkTable && pServerInfo->ThunkTable[pRpcMsg->ProcNum]) + pServerInfo->ThunkTable[pRpcMsg->ProcNum](&stubMsg); + else + { + SERVER_ROUTINE func; + LONG_PTR retval; + + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + { + SERVER_ROUTINE *vtbl = *(SERVER_ROUTINE **)((CStdStubBuffer *)pThis)->pvServerObject; + func = vtbl[pRpcMsg->ProcNum]; + } + else + func = pServerInfo->DispatchTable[pRpcMsg->ProcNum]; + + /* FIXME: what happens with return values that don't fit into a single register on x86? */ + retval = call_server_func(func, args, stack_size); + + if (retval_ptr) + { + TRACE("stub implementation returned 0x%lx\n", retval); + *retval_ptr = retval; + } + else + TRACE("void stub implementation\n"); + } + + stubMsg.Buffer = NULL; + stubMsg.BufferLength = 0; + + break; + case STUBLESS_GETBUFFER: + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) + NdrStubGetBuffer(pThis, pChannel, &stubMsg); + else + { + RPC_STATUS Status; + + pRpcMsg->BufferLength = stubMsg.BufferLength; + /* allocate buffer for [out] and [ret] params */ + Status = I_RpcGetBuffer(pRpcMsg); + if (Status) + RpcRaiseException(Status); + stubMsg.BufferStart = pRpcMsg->Buffer; + stubMsg.BufferEnd = stubMsg.BufferStart + stubMsg.BufferLength; + stubMsg.Buffer = stubMsg.BufferStart; + } + break; + case STUBLESS_MARSHAL: + case STUBLESS_UNMARSHAL: + case STUBLESS_CALCSIZE: + case STUBLESS_FREE: + current_offset = parameter_start_offset; + current_stack_offset = 0; + + /* NOTE: V1 style format does't terminate on the number_of_params + * condition as it doesn't have this attribute. Instead it + * terminates when the stack size given in the header is exceeded. + */ + for (i = 0; i < number_of_params; i++) + { + if (bV2Format) /* new parameter format */ + { + const NDR_PARAM_OIF_BASETYPE *pParam = + (const NDR_PARAM_OIF_BASETYPE *)&pFormat[current_offset]; + unsigned char *pArg; + + current_stack_offset = pParam->stack_offset; + pArg = (unsigned char *)(args+current_stack_offset); + + TRACE("param[%d]: new format\n", i); + TRACE("\tparam_attributes:"); dump_RPC_FC_PROC_PF(pParam->param_attributes); TRACE("\n"); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset); + TRACE("\tmemory addr (before): %p -> %p\n", pArg, *(unsigned char **)pArg); + + if (pParam->param_attributes.IsBasetype) + { + const unsigned char *pTypeFormat = + &pParam->type_format_char; + + TRACE("\tbase type: 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case STUBLESS_MARSHAL: + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) + { + if (pParam->param_attributes.IsSimpleRef) + call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + else + call_marshaller(&stubMsg, pArg, pTypeFormat); + } + break; + case STUBLESS_FREE: + if (pParam->param_attributes.ServerAllocSize) + HeapFree(GetProcessHeap(), 0, *(void **)pArg); + break; + case STUBLESS_UNMARSHAL: + if (pParam->param_attributes.ServerAllocSize) + *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pParam->param_attributes.ServerAllocSize * 8); + + if (pParam->param_attributes.IsIn) + { + if (pParam->param_attributes.IsSimpleRef) + call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0); + else + call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); + } + + /* make a note of the address of the return value parameter for later */ + if (pParam->param_attributes.IsReturn) + retval_ptr = (LONG_PTR *)pArg; + + break; + case STUBLESS_CALCSIZE: + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) + { + if (pParam->param_attributes.IsSimpleRef) + call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + else + call_buffer_sizer(&stubMsg, pArg, pTypeFormat); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_offset += sizeof(NDR_PARAM_OIF_BASETYPE); + } + else + { + const NDR_PARAM_OIF_OTHER *pParamOther = + (const NDR_PARAM_OIF_OTHER *)&pFormat[current_offset]; + + const unsigned char * pTypeFormat = + &(pStubDesc->pFormatTypes[pParamOther->type_offset]); + + TRACE("\tcomplex type 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case STUBLESS_MARSHAL: + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) + { + if (pParam->param_attributes.IsByValue) + call_marshaller(&stubMsg, pArg, pTypeFormat); + else + call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + } + break; + case STUBLESS_FREE: + if (pParam->param_attributes.MustFree) + { + if (pParam->param_attributes.IsByValue) + call_freer(&stubMsg, pArg, pTypeFormat); + else + call_freer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + } + + if (pParam->param_attributes.IsOut && + !pParam->param_attributes.IsIn && + !pParam->param_attributes.IsByValue && + !pParam->param_attributes.ServerAllocSize) + { + stubMsg.pfnFree(*(void **)pArg); + } + + if (pParam->param_attributes.ServerAllocSize) + HeapFree(GetProcessHeap(), 0, *(void **)pArg); + /* FIXME: call call_freer here for IN types with MustFree set */ + break; + case STUBLESS_UNMARSHAL: + if (pParam->param_attributes.ServerAllocSize) + *(void **)pArg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + pParam->param_attributes.ServerAllocSize * 8); + + if (pParam->param_attributes.IsIn) + { + if (pParam->param_attributes.IsByValue) + call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); + else + call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0); + } + else if (pParam->param_attributes.IsOut && + !pParam->param_attributes.ServerAllocSize && + !pParam->param_attributes.IsByValue) + { + DWORD size = calc_arg_size(&stubMsg, pTypeFormat); + + if(size) + { + *(void **)pArg = NdrAllocate(&stubMsg, size); + memset(*(void **)pArg, 0, size); + } + } + break; + case STUBLESS_CALCSIZE: + if (pParam->param_attributes.IsOut || pParam->param_attributes.IsReturn) + { + if (pParam->param_attributes.IsByValue) + call_buffer_sizer(&stubMsg, pArg, pTypeFormat); + else + call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + } + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_offset += sizeof(NDR_PARAM_OIF_OTHER); + } + TRACE("\tmemory addr (after): %p -> %p\n", pArg, *(unsigned char **)pArg); + } + else /* old parameter format */ + { + const NDR_PARAM_OI_BASETYPE *pParam = + (const NDR_PARAM_OI_BASETYPE *)&pFormat[current_offset]; + /* note: current_stack_offset starts after the This pointer + * if present, so adjust this */ + unsigned short current_stack_offset_adjusted = current_stack_offset + + ((pProcHeader->Oi_flags & RPC_FC_PROC_OIF_OBJECT) ? sizeof(void *) : 0); + unsigned char *pArg = (unsigned char *)(args+current_stack_offset_adjusted); + + /* no more parameters; exit loop */ + if (current_stack_offset_adjusted >= stack_size) + break; + + TRACE("param[%d]: old format\n", i); + TRACE("\tparam_direction: 0x%x\n", pParam->param_direction); + TRACE("\tstack_offset: 0x%x\n", current_stack_offset_adjusted); + + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE || + pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + { + const unsigned char *pTypeFormat = + &pParam->type_format_char; + + TRACE("\tbase type 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case STUBLESS_MARSHAL: + if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + call_marshaller(&stubMsg, pArg, pTypeFormat); + break; + case STUBLESS_FREE: + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) + call_freer(&stubMsg, pArg, pTypeFormat); + break; + case STUBLESS_UNMARSHAL: + if (pParam->param_direction == RPC_FC_IN_PARAM_BASETYPE) + call_unmarshaller(&stubMsg, &pArg, pTypeFormat, 0); + else if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + retval_ptr = (LONG_PTR *)pArg; + break; + case STUBLESS_CALCSIZE: + if (pParam->param_direction == RPC_FC_RETURN_PARAM_BASETYPE) + call_buffer_sizer(&stubMsg, pArg, pTypeFormat); + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_stack_offset += call_memory_sizer(&stubMsg, pTypeFormat); + current_offset += sizeof(NDR_PARAM_OI_BASETYPE); + } + else + { + const NDR_PARAM_OI_OTHER *pParamOther = + (const NDR_PARAM_OI_OTHER *)&pFormat[current_offset]; + + const unsigned char * pTypeFormat = + &pStubDesc->pFormatTypes[pParamOther->type_offset]; + + TRACE("\tcomplex type 0x%02x\n", *pTypeFormat); + + switch (phase) + { + case STUBLESS_MARSHAL: + if (pParam->param_direction == RPC_FC_OUT_PARAM || + pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_RETURN_PARAM) + call_marshaller(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + break; + case STUBLESS_FREE: + if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_IN_PARAM) + call_freer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + else if (pParam->param_direction == RPC_FC_OUT_PARAM) + stubMsg.pfnFree(*(void **)pArg); + break; + case STUBLESS_UNMARSHAL: + if (pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_IN_PARAM) + call_unmarshaller(&stubMsg, (unsigned char **)pArg, pTypeFormat, 0); + else if (pParam->param_direction == RPC_FC_RETURN_PARAM) + retval_ptr = (LONG_PTR *)pArg; + else if (pParam->param_direction == RPC_FC_OUT_PARAM) + { + DWORD size = calc_arg_size(&stubMsg, pTypeFormat); + + if(size) + { + *(void **)pArg = NdrAllocate(&stubMsg, size); + memset(*(void **)pArg, 0, size); + } + } + break; + case STUBLESS_CALCSIZE: + if (pParam->param_direction == RPC_FC_OUT_PARAM || + pParam->param_direction == RPC_FC_IN_OUT_PARAM || + pParam->param_direction == RPC_FC_RETURN_PARAM) + call_buffer_sizer(&stubMsg, *(unsigned char **)pArg, pTypeFormat); + break; + default: + RpcRaiseException(RPC_S_INTERNAL_ERROR); + } + + current_stack_offset += pParamOther->stack_size * sizeof(INT); + current_offset += sizeof(NDR_PARAM_OI_OTHER); + } + } + } + + break; + default: + ERR("shouldn't reach here. phase %d\n", phase); + break; + } + } + + pRpcMsg->BufferLength = (unsigned int)(stubMsg.Buffer - (unsigned char *)pRpcMsg->Buffer); + + if (ext_flags.HasNewCorrDesc) + { + /* free extra correlation package */ + /* NdrCorrelationFree(&stubMsg); */ + } + + if (Oif_flags.HasPipes) + { + /* NdrPipesDone(...) */ + } + + /* free the full pointer translation tables */ + if (pProcHeader->Oi_flags & RPC_FC_PROC_OIF_FULLPTR) + NdrFullPointerXlatFree(stubMsg.FullPtrXlatTables); + + /* free server function stack */ + HeapFree(GetProcessHeap(), 0, args); + + return S_OK; +} + +void WINAPI NdrServerCall2(PRPC_MESSAGE pRpcMsg) +{ + DWORD dwPhase; + NdrStubCall2(NULL, NULL, pRpcMsg, &dwPhase); +} diff --git a/reactos/dll/win32/rpcrt4_new/rpc_binding.c b/reactos/dll/win32/rpcrt4_new/rpc_binding.c new file mode 100644 index 00000000000..db30be63ba8 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_binding.c @@ -0,0 +1,1586 @@ +/* + * RPC binding API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2003 Mike Hearn + * Copyright 2004 Filip Navara + * Copyright 2006 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 +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winerror.h" +#include "winternl.h" +#include "wine/unicode.h" + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_message.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +LPSTR RPCRT4_strndupA(LPCSTR src, INT slen) +{ + DWORD len; + LPSTR s; + if (!src) return NULL; + if (slen == -1) slen = strlen(src); + len = slen; + s = HeapAlloc(GetProcessHeap(), 0, len+1); + memcpy(s, src, len); + s[len] = 0; + return s; +} + +LPSTR RPCRT4_strdupWtoA(LPCWSTR src) +{ + DWORD len; + LPSTR s; + if (!src) return NULL; + len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL); + s = HeapAlloc(GetProcessHeap(), 0, len); + WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL); + return s; +} + +LPWSTR RPCRT4_strdupAtoW(LPCSTR src) +{ + DWORD len; + LPWSTR s; + if (!src) return NULL; + len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); + s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, src, -1, s, len); + return s; +} + +static LPWSTR RPCRT4_strndupAtoW(LPCSTR src, INT slen) +{ + DWORD len; + LPWSTR s; + if (!src) return NULL; + len = MultiByteToWideChar(CP_ACP, 0, src, slen, NULL, 0); + s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, src, slen, s, len); + return s; +} + +LPWSTR RPCRT4_strndupW(LPCWSTR src, INT slen) +{ + DWORD len; + LPWSTR s; + if (!src) return NULL; + if (slen == -1) slen = strlenW(src); + len = slen; + s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR)); + memcpy(s, src, len*sizeof(WCHAR)); + s[len] = 0; + return s; +} + +void RPCRT4_strfree(LPSTR src) +{ + HeapFree(GetProcessHeap(), 0, src); +} + +static RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server) +{ + RpcBinding* NewBinding; + + NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding)); + NewBinding->refs = 1; + NewBinding->server = server; + + *Binding = NewBinding; + + return RPC_S_OK; +} + +static RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPCSTR Protseq) +{ + RpcBinding* NewBinding; + + RPCRT4_AllocBinding(&NewBinding, server); + NewBinding->Protseq = RPCRT4_strdupA(Protseq); + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +static RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPCWSTR Protseq) +{ + RpcBinding* NewBinding; + + RPCRT4_AllocBinding(&NewBinding, server); + NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq); + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +static RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPCSTR NetworkAddr, + LPCSTR Endpoint, LPCSTR NetworkOptions) +{ + RPC_STATUS status; + + TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding, + debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions)); + + RPCRT4_strfree(Binding->NetworkAddr); + Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + RPCRT4_strfree(Binding->Endpoint); + if (Endpoint) { + Binding->Endpoint = RPCRT4_strdupA(Endpoint); + } else { + Binding->Endpoint = RPCRT4_strdupA(""); + } + HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions); + Binding->NetworkOptions = RPCRT4_strdupAtoW(NetworkOptions); + if (!Binding->Endpoint) ERR("out of memory?\n"); + + status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr, + Binding->Endpoint, Binding->NetworkOptions, + &Binding->Assoc); + if (status != RPC_S_OK) + return status; + + return RPC_S_OK; +} + +static RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPCWSTR NetworkAddr, + LPCWSTR Endpoint, LPCWSTR NetworkOptions) +{ + RPC_STATUS status; + + TRACE("(RpcBinding == ^%p, NetworkAddr == %s, EndPoint == %s, NetworkOptions == %s)\n", Binding, + debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions)); + + RPCRT4_strfree(Binding->NetworkAddr); + Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr); + RPCRT4_strfree(Binding->Endpoint); + if (Endpoint) { + Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint); + } else { + Binding->Endpoint = RPCRT4_strdupA(""); + } + if (!Binding->Endpoint) ERR("out of memory?\n"); + HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions); + Binding->NetworkOptions = RPCRT4_strdupW(NetworkOptions); + + status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr, + Binding->Endpoint, Binding->NetworkOptions, + &Binding->Assoc); + if (status != RPC_S_OK) + return status; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPCSTR Endpoint) +{ + RPC_STATUS status; + + TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint); + + RPCRT4_strfree(Binding->Endpoint); + Binding->Endpoint = RPCRT4_strdupA(Endpoint); + + RpcAssoc_Release(Binding->Assoc); + Binding->Assoc = NULL; + status = RPCRT4_GetAssociation(Binding->Protseq, Binding->NetworkAddr, + Binding->Endpoint, Binding->NetworkOptions, + &Binding->Assoc); + if (status != RPC_S_OK) + return status; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, const UUID* ObjectUuid) +{ + TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid)); + if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID)); + else UuidCreateNil(&Binding->ObjectUuid); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection) +{ + RpcBinding* NewBinding; + TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding, Connection); + + RPCRT4_AllocBinding(&NewBinding, Connection->server); + NewBinding->Protseq = RPCRT4_strdupA(rpcrt4_conn_get_name(Connection)); + NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr); + NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint); + NewBinding->FromConn = Connection; + + TRACE("binding: %p\n", NewBinding); + *Binding = NewBinding; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding) +{ + InterlockedIncrement(&OldBinding->refs); + *Binding = OldBinding; + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding) +{ + if (InterlockedDecrement(&Binding->refs)) + return RPC_S_OK; + + TRACE("binding: %p\n", Binding); + if (Binding->Assoc) RpcAssoc_Release(Binding->Assoc); + RPCRT4_strfree(Binding->Endpoint); + RPCRT4_strfree(Binding->NetworkAddr); + RPCRT4_strfree(Binding->Protseq); + HeapFree(GetProcessHeap(), 0, Binding->NetworkOptions); + if (Binding->AuthInfo) RpcAuthInfo_Release(Binding->AuthInfo); + if (Binding->QOS) RpcQualityOfService_Release(Binding->QOS); + HeapFree(GetProcessHeap(), 0, Binding); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, + PRPC_SYNTAX_IDENTIFIER TransferSyntax, + PRPC_SYNTAX_IDENTIFIER InterfaceId) +{ + TRACE("(Binding == ^%p)\n", Binding); + + if (!Binding->server) { + return RpcAssoc_GetClientConnection(Binding->Assoc, InterfaceId, + TransferSyntax, Binding->AuthInfo, Binding->QOS, Connection); + } else { + /* we already have a connection with acceptable binding, so use it */ + if (Binding->FromConn) { + *Connection = Binding->FromConn; + return RPC_S_OK; + } else { + ERR("no connection in binding\n"); + return RPC_S_INTERNAL_ERROR; + } + } +} + +RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection) +{ + TRACE("(Binding == ^%p)\n", Binding); + if (!Connection) return RPC_S_OK; + if (Binding->server) { + /* don't destroy a connection that is cached in the binding */ + if (Binding->FromConn == Connection) + return RPC_S_OK; + return RPCRT4_DestroyConnection(Connection); + } + else { + RpcAssoc_ReleaseIdleConnection(Binding->Assoc, Connection); + return RPC_S_OK; + } +} + +/* utility functions for string composing and parsing */ +static unsigned RPCRT4_strcopyA(LPSTR data, LPCSTR src) +{ + unsigned len = strlen(src); + memcpy(data, src, len*sizeof(CHAR)); + return len; +} + +static unsigned RPCRT4_strcopyW(LPWSTR data, LPCWSTR src) +{ + unsigned len = strlenW(src); + memcpy(data, src, len*sizeof(WCHAR)); + return len; +} + +static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src) +{ + DWORD len = strlen(dst), slen = strlen(src); + LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR)); + if (!ndst) + { + HeapFree(GetProcessHeap(), 0, dst); + return NULL; + } + ndst[len] = ','; + memcpy(ndst+len+1, src, slen+1); + return ndst; +} + +static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src) +{ + DWORD len = strlenW(dst), slen = strlenW(src); + LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR)); + if (!ndst) + { + HeapFree(GetProcessHeap(), 0, dst); + return NULL; + } + ndst[len] = ','; + memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR)); + return ndst; +} + + +/*********************************************************************** + * RpcStringBindingComposeA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingComposeA(RPC_CSTR ObjUuid, RPC_CSTR Protseq, + RPC_CSTR NetworkAddr, RPC_CSTR Endpoint, + RPC_CSTR Options, RPC_CSTR *StringBinding ) +{ + DWORD len = 1; + LPSTR data; + + TRACE( "(%s,%s,%s,%s,%s,%p)\n", + debugstr_a( (char*)ObjUuid ), debugstr_a( (char*)Protseq ), + debugstr_a( (char*)NetworkAddr ), debugstr_a( (char*)Endpoint ), + debugstr_a( (char*)Options ), StringBinding ); + + if (ObjUuid && *ObjUuid) len += strlen((char*)ObjUuid) + 1; + if (Protseq && *Protseq) len += strlen((char*)Protseq) + 1; + if (NetworkAddr && *NetworkAddr) len += strlen((char*)NetworkAddr); + if (Endpoint && *Endpoint) len += strlen((char*)Endpoint) + 2; + if (Options && *Options) len += strlen((char*)Options) + 2; + + data = HeapAlloc(GetProcessHeap(), 0, len); + *StringBinding = (unsigned char*)data; + + if (ObjUuid && *ObjUuid) { + data += RPCRT4_strcopyA(data, (char*)ObjUuid); + *data++ = '@'; + } + if (Protseq && *Protseq) { + data += RPCRT4_strcopyA(data, (char*)Protseq); + *data++ = ':'; + } + if (NetworkAddr && *NetworkAddr) + data += RPCRT4_strcopyA(data, (char*)NetworkAddr); + + if ((Endpoint && *Endpoint) || + (Options && *Options)) { + *data++ = '['; + if (Endpoint && *Endpoint) { + data += RPCRT4_strcopyA(data, (char*)Endpoint); + if (Options && *Options) *data++ = ','; + } + if (Options && *Options) { + data += RPCRT4_strcopyA(data, (char*)Options); + } + *data++ = ']'; + } + *data = 0; + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcStringBindingComposeW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingComposeW( RPC_WSTR ObjUuid, RPC_WSTR Protseq, + RPC_WSTR NetworkAddr, RPC_WSTR Endpoint, + RPC_WSTR Options, RPC_WSTR* StringBinding ) +{ + DWORD len = 1; + RPC_WSTR data; + + TRACE("(%s,%s,%s,%s,%s,%p)\n", + debugstr_w( ObjUuid ), debugstr_w( Protseq ), + debugstr_w( NetworkAddr ), debugstr_w( Endpoint ), + debugstr_w( Options ), StringBinding); + + if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) + 1; + if (Protseq && *Protseq) len += strlenW(Protseq) + 1; + if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr); + if (Endpoint && *Endpoint) len += strlenW(Endpoint) + 2; + if (Options && *Options) len += strlenW(Options) + 2; + + data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR)); + *StringBinding = data; + + if (ObjUuid && *ObjUuid) { + data += RPCRT4_strcopyW(data, ObjUuid); + *data++ = '@'; + } + if (Protseq && *Protseq) { + data += RPCRT4_strcopyW(data, Protseq); + *data++ = ':'; + } + if (NetworkAddr && *NetworkAddr) { + data += RPCRT4_strcopyW(data, NetworkAddr); + } + if ((Endpoint && *Endpoint) || + (Options && *Options)) { + *data++ = '['; + if (Endpoint && *Endpoint) { + data += RPCRT4_strcopyW(data, Endpoint); + if (Options && *Options) *data++ = ','; + } + if (Options && *Options) { + data += RPCRT4_strcopyW(data, Options); + } + *data++ = ']'; + } + *data = 0; + + return RPC_S_OK; +} + + +/*********************************************************************** + * RpcStringBindingParseA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingParseA( RPC_CSTR StringBinding, RPC_CSTR *ObjUuid, + RPC_CSTR *Protseq, RPC_CSTR *NetworkAddr, + RPC_CSTR *Endpoint, RPC_CSTR *Options) +{ + CHAR *data, *next; + static const char ep_opt[] = "endpoint="; + + TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a((char*)StringBinding), + ObjUuid, Protseq, NetworkAddr, Endpoint, Options); + + if (ObjUuid) *ObjUuid = NULL; + if (Protseq) *Protseq = NULL; + if (NetworkAddr) *NetworkAddr = NULL; + if (Endpoint) *Endpoint = NULL; + if (Options) *Options = NULL; + + data = (char*) StringBinding; + + next = strchr(data, '@'); + if (next) { + if (ObjUuid) *ObjUuid = (unsigned char*)RPCRT4_strndupA(data, next - data); + data = next+1; + } + + next = strchr(data, ':'); + if (next) { + if (Protseq) *Protseq = (unsigned char*)RPCRT4_strndupA(data, next - data); + data = next+1; + } + + next = strchr(data, '['); + if (next) { + CHAR *close, *opt; + + if (NetworkAddr) *NetworkAddr = (unsigned char*)RPCRT4_strndupA(data, next - data); + data = next+1; + close = strchr(data, ']'); + if (!close) goto fail; + + /* tokenize options */ + while (data < close) { + next = strchr(data, ','); + if (!next || next > close) next = close; + /* FIXME: this is kind of inefficient */ + opt = RPCRT4_strndupA(data, next - data); + data = next+1; + + /* parse option */ + next = strchr(opt, '='); + if (!next) { + /* not an option, must be an endpoint */ + if (*Endpoint) goto fail; + *Endpoint = (unsigned char*) opt; + } else { + if (strncmp(opt, ep_opt, strlen(ep_opt)) == 0) { + /* endpoint option */ + if (*Endpoint) goto fail; + *Endpoint = (unsigned char*) RPCRT4_strdupA(next+1); + HeapFree(GetProcessHeap(), 0, opt); + } else { + /* network option */ + if (*Options) { + /* FIXME: this is kind of inefficient */ + *Options = (unsigned char*) RPCRT4_strconcatA( (char*)*Options, opt); + HeapFree(GetProcessHeap(), 0, opt); + } else + *Options = (unsigned char*) opt; + } + } + } + + data = close+1; + if (*data) goto fail; + } + else if (NetworkAddr) + *NetworkAddr = (unsigned char*)RPCRT4_strdupA(data); + + return RPC_S_OK; + +fail: + if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid); + if (Protseq) RpcStringFreeA((unsigned char**)Protseq); + if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr); + if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint); + if (Options) RpcStringFreeA((unsigned char**)Options); + return RPC_S_INVALID_STRING_BINDING; +} + +/*********************************************************************** + * RpcStringBindingParseW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcStringBindingParseW( RPC_WSTR StringBinding, RPC_WSTR *ObjUuid, + RPC_WSTR *Protseq, RPC_WSTR *NetworkAddr, + RPC_WSTR *Endpoint, RPC_WSTR *Options) +{ + WCHAR *data, *next; + static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0}; + + TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding), + ObjUuid, Protseq, NetworkAddr, Endpoint, Options); + + if (ObjUuid) *ObjUuid = NULL; + if (Protseq) *Protseq = NULL; + if (NetworkAddr) *NetworkAddr = NULL; + if (Endpoint) *Endpoint = NULL; + if (Options) *Options = NULL; + + data = StringBinding; + + next = strchrW(data, '@'); + if (next) { + if (ObjUuid) *ObjUuid = RPCRT4_strndupW(data, next - data); + data = next+1; + } + + next = strchrW(data, ':'); + if (next) { + if (Protseq) *Protseq = RPCRT4_strndupW(data, next - data); + data = next+1; + } + + next = strchrW(data, '['); + if (next) { + WCHAR *close, *opt; + + if (NetworkAddr) *NetworkAddr = RPCRT4_strndupW(data, next - data); + data = next+1; + close = strchrW(data, ']'); + if (!close) goto fail; + + /* tokenize options */ + while (data < close) { + next = strchrW(data, ','); + if (!next || next > close) next = close; + /* FIXME: this is kind of inefficient */ + opt = RPCRT4_strndupW(data, next - data); + data = next+1; + + /* parse option */ + next = strchrW(opt, '='); + if (!next) { + /* not an option, must be an endpoint */ + if (*Endpoint) goto fail; + *Endpoint = opt; + } else { + if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) { + /* endpoint option */ + if (*Endpoint) goto fail; + *Endpoint = RPCRT4_strdupW(next+1); + HeapFree(GetProcessHeap(), 0, opt); + } else { + /* network option */ + if (*Options) { + /* FIXME: this is kind of inefficient */ + *Options = RPCRT4_strconcatW(*Options, opt); + HeapFree(GetProcessHeap(), 0, opt); + } else + *Options = opt; + } + } + } + + data = close+1; + if (*data) goto fail; + } else if (NetworkAddr) + *NetworkAddr = RPCRT4_strdupW(data); + + return RPC_S_OK; + +fail: + if (ObjUuid) RpcStringFreeW(ObjUuid); + if (Protseq) RpcStringFreeW(Protseq); + if (NetworkAddr) RpcStringFreeW(NetworkAddr); + if (Endpoint) RpcStringFreeW(Endpoint); + if (Options) RpcStringFreeW(Options); + return RPC_S_INVALID_STRING_BINDING; +} + +/*********************************************************************** + * RpcBindingFree (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS status; + TRACE("(%p) = %p\n", Binding, *Binding); + status = RPCRT4_DestroyBinding(*Binding); + if (status == RPC_S_OK) *Binding = 0; + return status; +} + +/*********************************************************************** + * RpcBindingVectorFree (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector ) +{ + RPC_STATUS status; + unsigned long c; + + TRACE("(%p)\n", BindingVector); + for (c=0; c<(*BindingVector)->Count; c++) { + status = RpcBindingFree(&(*BindingVector)->BindingH[c]); + } + HeapFree(GetProcessHeap(), 0, *BindingVector); + *BindingVector = NULL; + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingInqObject (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid)); + memcpy(ObjectUuid, &bind->ObjectUuid, sizeof(UUID)); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingSetObject (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid)); + if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING; + return RPCRT4_SetBindingObject(Binding, ObjectUuid); +} + +/*********************************************************************** + * RpcBindingFromStringBindingA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFromStringBindingA( RPC_CSTR StringBinding, RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS ret; + RpcBinding* bind = NULL; + RPC_CSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; + UUID Uuid; + + TRACE("(%s,%p)\n", debugstr_a((char*)StringBinding), Binding); + + ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq, + &NetworkAddr, &Endpoint, &Options); + if (ret != RPC_S_OK) return ret; + + ret = UuidFromStringA(ObjectUuid, &Uuid); + + if (ret == RPC_S_OK) + ret = RPCRT4_CreateBindingA(&bind, FALSE, (char*)Protseq); + if (ret == RPC_S_OK) + ret = RPCRT4_SetBindingObject(bind, &Uuid); + if (ret == RPC_S_OK) + ret = RPCRT4_CompleteBindingA(bind, (char*)NetworkAddr, (char*)Endpoint, (char*)Options); + + RpcStringFreeA((unsigned char**)&Options); + RpcStringFreeA((unsigned char**)&Endpoint); + RpcStringFreeA((unsigned char**)&NetworkAddr); + RpcStringFreeA((unsigned char**)&Protseq); + RpcStringFreeA((unsigned char**)&ObjectUuid); + + if (ret == RPC_S_OK) + *Binding = (RPC_BINDING_HANDLE)bind; + else + RPCRT4_DestroyBinding(bind); + + return ret; +} + +/*********************************************************************** + * RpcBindingFromStringBindingW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingFromStringBindingW( RPC_WSTR StringBinding, RPC_BINDING_HANDLE* Binding ) +{ + RPC_STATUS ret; + RpcBinding* bind = NULL; + RPC_WSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options; + UUID Uuid; + + TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding); + + ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq, + &NetworkAddr, &Endpoint, &Options); + if (ret != RPC_S_OK) return ret; + + ret = UuidFromStringW(ObjectUuid, &Uuid); + + if (ret == RPC_S_OK) + ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq); + if (ret == RPC_S_OK) + ret = RPCRT4_SetBindingObject(bind, &Uuid); + if (ret == RPC_S_OK) + ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options); + + RpcStringFreeW(&Options); + RpcStringFreeW(&Endpoint); + RpcStringFreeW(&NetworkAddr); + RpcStringFreeW(&Protseq); + RpcStringFreeW(&ObjectUuid); + + if (ret == RPC_S_OK) + *Binding = (RPC_BINDING_HANDLE)bind; + else + RPCRT4_DestroyBinding(bind); + + return ret; +} + +/*********************************************************************** + * RpcBindingToStringBindingA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, RPC_CSTR *StringBinding ) +{ + RPC_STATUS ret; + RpcBinding* bind = (RpcBinding*)Binding; + RPC_CSTR ObjectUuid; + + TRACE("(%p,%p)\n", Binding, StringBinding); + + ret = UuidToStringA(&bind->ObjectUuid, &ObjectUuid); + if (ret != RPC_S_OK) return ret; + + ret = RpcStringBindingComposeA(ObjectUuid, (unsigned char*)bind->Protseq, (unsigned char*) bind->NetworkAddr, + (unsigned char*) bind->Endpoint, NULL, StringBinding); + + RpcStringFreeA(&ObjectUuid); + + return ret; +} + +/*********************************************************************** + * RpcBindingToStringBindingW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, RPC_WSTR *StringBinding ) +{ + RPC_STATUS ret; + unsigned char *str = NULL; + TRACE("(%p,%p)\n", Binding, StringBinding); + ret = RpcBindingToStringBindingA(Binding, &str); + *StringBinding = RPCRT4_strdupAtoW((char*)str); + RpcStringFreeA((unsigned char**)&str); + return ret; +} + +/*********************************************************************** + * I_RpcBindingSetAsync (RPCRT4.@) + * NOTES + * Exists in win9x and winNT, but with different number of arguments + * (9x version has 3 arguments, NT has 2). + */ +RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn) +{ + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE( "(%p,%p): stub\n", Binding, BlockingFn ); + + bind->BlockingFn = BlockingFn; + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingCopy (RPCRT4.@) + */ +RPC_STATUS RPC_ENTRY RpcBindingCopy( + RPC_BINDING_HANDLE SourceBinding, + RPC_BINDING_HANDLE* DestinationBinding) +{ + RpcBinding *DestBinding; + RpcBinding *SrcBinding = (RpcBinding*)SourceBinding; + RPC_STATUS status; + + TRACE("(%p, %p)\n", SourceBinding, DestinationBinding); + + status = RPCRT4_AllocBinding(&DestBinding, SrcBinding->server); + if (status != RPC_S_OK) return status; + + DestBinding->ObjectUuid = SrcBinding->ObjectUuid; + DestBinding->BlockingFn = SrcBinding->BlockingFn; + DestBinding->Protseq = RPCRT4_strndupA(SrcBinding->Protseq, -1); + DestBinding->NetworkAddr = RPCRT4_strndupA(SrcBinding->NetworkAddr, -1); + DestBinding->Endpoint = RPCRT4_strndupA(SrcBinding->Endpoint, -1); + DestBinding->NetworkOptions = RPCRT4_strdupW(SrcBinding->NetworkOptions); + if (SrcBinding->Assoc) SrcBinding->Assoc->refs++; + DestBinding->Assoc = SrcBinding->Assoc; + + if (SrcBinding->AuthInfo) RpcAuthInfo_AddRef(SrcBinding->AuthInfo); + DestBinding->AuthInfo = SrcBinding->AuthInfo; + if (SrcBinding->QOS) RpcQualityOfService_AddRef(SrcBinding->QOS); + DestBinding->QOS = SrcBinding->QOS; + + *DestinationBinding = DestBinding; + return RPC_S_OK; +} + +/*********************************************************************** + * RpcImpersonateClient (RPCRT4.@) + * + * Impersonates the client connected via a binding handle so that security + * checks are done in the context of the client. + * + * PARAMS + * BindingHandle [I] Handle to the binding to the client. + * + * RETURNS + * Success: RPS_S_OK. + * Failure: RPC_STATUS value. + * + * NOTES + * + * If BindingHandle is NULL then the function impersonates the client + * connected to the binding handle of the current thread. + */ +RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle) +{ + FIXME("(%p): stub\n", BindingHandle); + ImpersonateSelf(SecurityImpersonation); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcRevertToSelfEx (RPCRT4.@) + * + * Stops impersonating the client connected to the binding handle so that security + * checks are no longer done in the context of the client. + * + * PARAMS + * BindingHandle [I] Handle to the binding to the client. + * + * RETURNS + * Success: RPS_S_OK. + * Failure: RPC_STATUS value. + * + * NOTES + * + * If BindingHandle is NULL then the function stops impersonating the client + * connected to the binding handle of the current thread. + */ +RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle) +{ + FIXME("(%p): stub\n", BindingHandle); + return RPC_S_OK; +} + +static inline BOOL has_nt_auth_identity(ULONG AuthnLevel) +{ + switch (AuthnLevel) + { + case RPC_C_AUTHN_GSS_NEGOTIATE: + case RPC_C_AUTHN_WINNT: + case RPC_C_AUTHN_GSS_KERBEROS: + return TRUE; + default: + return FALSE; + } +} + +static RPC_STATUS RpcAuthInfo_Create(ULONG AuthnLevel, ULONG AuthnSvc, + CredHandle cred, TimeStamp exp, + ULONG cbMaxToken, + RPC_AUTH_IDENTITY_HANDLE identity, + RpcAuthInfo **ret) +{ + RpcAuthInfo *AuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo)); + if (!AuthInfo) + return ERROR_OUTOFMEMORY; + + AuthInfo->refs = 1; + AuthInfo->AuthnLevel = AuthnLevel; + AuthInfo->AuthnSvc = AuthnSvc; + AuthInfo->cred = cred; + AuthInfo->exp = exp; + AuthInfo->cbMaxToken = cbMaxToken; + AuthInfo->identity = identity; + + /* duplicate the SEC_WINNT_AUTH_IDENTITY structure, if applicable, to + * enable better matching in RpcAuthInfo_IsEqual */ + if (identity && has_nt_auth_identity(AuthnSvc)) + { + const SEC_WINNT_AUTH_IDENTITY_W *nt_identity = identity; + AuthInfo->nt_identity = HeapAlloc(GetProcessHeap(), 0, sizeof(*AuthInfo->nt_identity)); + if (!AuthInfo->nt_identity) + { + HeapFree(GetProcessHeap(), 0, AuthInfo); + return ERROR_OUTOFMEMORY; + } + + AuthInfo->nt_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) + AuthInfo->nt_identity->User = RPCRT4_strndupW(nt_identity->User, nt_identity->UserLength); + else + AuthInfo->nt_identity->User = RPCRT4_strndupAtoW((const char *)nt_identity->User, nt_identity->UserLength); + AuthInfo->nt_identity->UserLength = nt_identity->UserLength; + if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) + AuthInfo->nt_identity->Domain = RPCRT4_strndupW(nt_identity->Domain, nt_identity->DomainLength); + else + AuthInfo->nt_identity->Domain = RPCRT4_strndupAtoW((const char *)nt_identity->Domain, nt_identity->DomainLength); + AuthInfo->nt_identity->DomainLength = nt_identity->DomainLength; + if (nt_identity->Flags & SEC_WINNT_AUTH_IDENTITY_UNICODE) + AuthInfo->nt_identity->Password = RPCRT4_strndupW(nt_identity->Password, nt_identity->PasswordLength); + else + AuthInfo->nt_identity->Password = RPCRT4_strndupAtoW((const char *)nt_identity->Password, nt_identity->PasswordLength); + AuthInfo->nt_identity->PasswordLength = nt_identity->PasswordLength; + + if (!AuthInfo->nt_identity->User || + !AuthInfo->nt_identity->Domain || + !AuthInfo->nt_identity->Password) + { + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User); + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Domain); + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Password); + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity); + HeapFree(GetProcessHeap(), 0, AuthInfo); + return ERROR_OUTOFMEMORY; + } + } + else + AuthInfo->nt_identity = NULL; + *ret = AuthInfo; + return RPC_S_OK; +} + +ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo) +{ + return InterlockedIncrement(&AuthInfo->refs); +} + +ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo) +{ + ULONG refs = InterlockedDecrement(&AuthInfo->refs); + + if (!refs) + { + FreeCredentialsHandle(&AuthInfo->cred); + if (AuthInfo->nt_identity) + { + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User); + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->Domain); + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity->User); + HeapFree(GetProcessHeap(), 0, AuthInfo->nt_identity); + } + HeapFree(GetProcessHeap(), 0, AuthInfo); + } + + return refs; +} + +BOOL RpcAuthInfo_IsEqual(const RpcAuthInfo *AuthInfo1, const RpcAuthInfo *AuthInfo2) +{ + if (AuthInfo1 == AuthInfo2) + return TRUE; + + if (!AuthInfo1 || !AuthInfo2) + return FALSE; + + if ((AuthInfo1->AuthnLevel != AuthInfo2->AuthnLevel) || + (AuthInfo1->AuthnSvc != AuthInfo2->AuthnSvc)) + return FALSE; + + if (AuthInfo1->identity == AuthInfo2->identity) + return TRUE; + + if (!AuthInfo1->identity || !AuthInfo2->identity) + return FALSE; + + if (has_nt_auth_identity(AuthInfo1->AuthnSvc)) + { + const SEC_WINNT_AUTH_IDENTITY_W *identity1 = AuthInfo1->nt_identity; + const SEC_WINNT_AUTH_IDENTITY_W *identity2 = AuthInfo2->nt_identity; + /* compare user names */ + if (identity1->UserLength != identity2->UserLength || + memcmp(identity1->User, identity2->User, identity1->UserLength)) + return FALSE; + /* compare domain names */ + if (identity1->DomainLength != identity2->DomainLength || + memcmp(identity1->Domain, identity2->Domain, identity1->DomainLength)) + return FALSE; + /* compare passwords */ + if (identity1->PasswordLength != identity2->PasswordLength || + memcmp(identity1->Password, identity2->Password, identity1->PasswordLength)) + return FALSE; + } + else + return FALSE; + + return TRUE; +} + +static RPC_STATUS RpcQualityOfService_Create(const RPC_SECURITY_QOS *qos_src, BOOL unicode, RpcQualityOfService **qos_dst) +{ + RpcQualityOfService *qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos)); + + if (!qos) + return RPC_S_OUT_OF_RESOURCES; + + qos->refs = 1; + qos->qos = HeapAlloc(GetProcessHeap(), 0, sizeof(*qos->qos)); + if (!qos->qos) goto error; + qos->qos->Version = qos_src->Version; + qos->qos->Capabilities = qos_src->Capabilities; + qos->qos->IdentityTracking = qos_src->IdentityTracking; + qos->qos->ImpersonationType = qos_src->ImpersonationType; + qos->qos->AdditionalSecurityInfoType = 0; + + if (qos_src->Version >= 2) + { + const RPC_SECURITY_QOS_V2_W *qos_src2 = (const RPC_SECURITY_QOS_V2_W *)qos_src; + qos->qos->AdditionalSecurityInfoType = qos_src2->AdditionalSecurityInfoType; + if (qos_src2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + { + const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_src = qos_src2->u.HttpCredentials; + RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials_dst; + + http_credentials_dst = HeapAlloc(GetProcessHeap(), 0, sizeof(*http_credentials_dst)); + qos->qos->u.HttpCredentials = http_credentials_dst; + if (!http_credentials_dst) goto error; + http_credentials_dst->TransportCredentials = NULL; + http_credentials_dst->Flags = http_credentials_src->Flags; + http_credentials_dst->AuthenticationTarget = http_credentials_src->AuthenticationTarget; + http_credentials_dst->NumberOfAuthnSchemes = http_credentials_src->NumberOfAuthnSchemes; + http_credentials_dst->AuthnSchemes = NULL; + http_credentials_dst->ServerCertificateSubject = NULL; + if (http_credentials_src->TransportCredentials) + { + SEC_WINNT_AUTH_IDENTITY_W *cred_dst; + cred_dst = http_credentials_dst->TransportCredentials = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cred_dst)); + if (!cred_dst) goto error; + cred_dst->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE; + if (unicode) + { + const SEC_WINNT_AUTH_IDENTITY_W *cred_src = http_credentials_src->TransportCredentials; + cred_dst->UserLength = cred_src->UserLength; + cred_dst->PasswordLength = cred_src->PasswordLength; + cred_dst->DomainLength = cred_src->DomainLength; + cred_dst->User = RPCRT4_strndupW(cred_src->User, cred_src->UserLength); + cred_dst->Password = RPCRT4_strndupW(cred_src->Password, cred_src->PasswordLength); + cred_dst->Domain = RPCRT4_strndupW(cred_src->Domain, cred_src->DomainLength); + } + else + { + const SEC_WINNT_AUTH_IDENTITY_A *cred_src = (const SEC_WINNT_AUTH_IDENTITY_A *)http_credentials_src->TransportCredentials; + cred_dst->UserLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, NULL, 0); + cred_dst->DomainLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, NULL, 0); + cred_dst->PasswordLength = MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, NULL, 0); + cred_dst->User = HeapAlloc(GetProcessHeap(), 0, cred_dst->UserLength * sizeof(WCHAR)); + cred_dst->Password = HeapAlloc(GetProcessHeap(), 0, cred_dst->PasswordLength * sizeof(WCHAR)); + cred_dst->Domain = HeapAlloc(GetProcessHeap(), 0, cred_dst->DomainLength * sizeof(WCHAR)); + if (!cred_dst || !cred_dst->Password || !cred_dst->Domain) goto error; + MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->User, cred_src->UserLength, cred_dst->User, cred_dst->UserLength); + MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Domain, cred_src->DomainLength, cred_dst->Domain, cred_dst->DomainLength); + MultiByteToWideChar(CP_ACP, 0, (char *)cred_src->Password, cred_src->PasswordLength, cred_dst->Password, cred_dst->PasswordLength); + } + } + if (http_credentials_src->NumberOfAuthnSchemes) + { + http_credentials_dst->AuthnSchemes = HeapAlloc(GetProcessHeap(), 0, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes)); + if (!http_credentials_dst->AuthnSchemes) goto error; + memcpy(http_credentials_dst->AuthnSchemes, http_credentials_src->AuthnSchemes, http_credentials_src->NumberOfAuthnSchemes * sizeof(*http_credentials_dst->AuthnSchemes)); + } + if (http_credentials_src->ServerCertificateSubject) + { + if (unicode) + http_credentials_dst->ServerCertificateSubject = + RPCRT4_strndupW(http_credentials_src->ServerCertificateSubject, + strlenW(http_credentials_src->ServerCertificateSubject)); + else + http_credentials_dst->ServerCertificateSubject = + RPCRT4_strdupAtoW((char *)http_credentials_src->ServerCertificateSubject); + if (!http_credentials_dst->ServerCertificateSubject) goto error; + } + } + } + *qos_dst = qos; + return RPC_S_OK; + +error: + if (qos->qos) + { + if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP && + qos->qos->u.HttpCredentials) + { + if (qos->qos->u.HttpCredentials->TransportCredentials) + { + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos); + } + HeapFree(GetProcessHeap(), 0, qos); + return RPC_S_OUT_OF_RESOURCES; +} + +ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos) +{ + return InterlockedIncrement(&qos->refs); +} + +ULONG RpcQualityOfService_Release(RpcQualityOfService *qos) +{ + ULONG refs = InterlockedDecrement(&qos->refs); + + if (!refs) + { + if (qos->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + { + if (qos->qos->u.HttpCredentials->TransportCredentials) + { + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->User); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Domain); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials->Password); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->TransportCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->AuthnSchemes); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials->ServerCertificateSubject); + HeapFree(GetProcessHeap(), 0, qos->qos->u.HttpCredentials); + } + HeapFree(GetProcessHeap(), 0, qos->qos); + HeapFree(GetProcessHeap(), 0, qos); + } + return refs; +} + +BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQualityOfService *qos2) +{ + if (qos1 == qos2) + return TRUE; + + if (!qos1 || !qos2) + return FALSE; + + TRACE("qos1 = { %ld %ld %ld %ld }, qos2 = { %ld %ld %ld %ld }\n", + qos1->qos->Capabilities, qos1->qos->IdentityTracking, + qos1->qos->ImpersonationType, qos1->qos->AdditionalSecurityInfoType, + qos2->qos->Capabilities, qos2->qos->IdentityTracking, + qos2->qos->ImpersonationType, qos2->qos->AdditionalSecurityInfoType); + + if ((qos1->qos->Capabilities != qos2->qos->Capabilities) || + (qos1->qos->IdentityTracking != qos2->qos->IdentityTracking) || + (qos1->qos->ImpersonationType != qos2->qos->ImpersonationType) || + (qos1->qos->AdditionalSecurityInfoType != qos2->qos->AdditionalSecurityInfoType)) + return FALSE; + + if (qos1->qos->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + { + const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials1 = qos1->qos->u.HttpCredentials; + const RPC_HTTP_TRANSPORT_CREDENTIALS_W *http_credentials2 = qos2->qos->u.HttpCredentials; + + if (http_credentials1->Flags != http_credentials2->Flags) + return FALSE; + + if (http_credentials1->AuthenticationTarget != http_credentials2->AuthenticationTarget) + return FALSE; + + /* authentication schemes and server certificate subject not currently used */ + + if (http_credentials1->TransportCredentials != http_credentials2->TransportCredentials) + { + const SEC_WINNT_AUTH_IDENTITY_W *identity1 = http_credentials1->TransportCredentials; + const SEC_WINNT_AUTH_IDENTITY_W *identity2 = http_credentials2->TransportCredentials; + + if (!identity1 || !identity2) + return FALSE; + + /* compare user names */ + if (identity1->UserLength != identity2->UserLength || + memcmp(identity1->User, identity2->User, identity1->UserLength)) + return FALSE; + /* compare domain names */ + if (identity1->DomainLength != identity2->DomainLength || + memcmp(identity1->Domain, identity2->Domain, identity1->DomainLength)) + return FALSE; + /* compare passwords */ + if (identity1->PasswordLength != identity2->PasswordLength || + memcmp(identity1->Password, identity2->Password, identity1->PasswordLength)) + return FALSE; + } + } + + return TRUE; +} + +/*********************************************************************** + * RpcRevertToSelf (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcRevertToSelf(void) +{ + FIXME("stub\n"); + RevertToSelf(); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcMgmtSetComTimeout (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtSetComTimeout(RPC_BINDING_HANDLE BindingHandle, unsigned int Timeout) +{ + FIXME("(%p, %d): stub\n", BindingHandle, Timeout); + return RPC_S_OK; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoExA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc, + ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS ) +{ + FIXME("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoExW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc, + ULONG RpcQosVersion, RPC_SECURITY_QOS *SecurityQOS ) +{ + FIXME("%p %p %p %p %p %p %u %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc, RpcQosVersion, SecurityQOS); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc ) +{ + FIXME("%p %p %p %p %p %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingInqAuthInfoW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingInqAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR *ServerPrincName, ULONG *AuthnLevel, + ULONG *AuthnSvc, RPC_AUTH_IDENTITY_HANDLE *AuthIdentity, ULONG *AuthzSvc ) +{ + FIXME("%p %p %p %p %p %p\n", Binding, ServerPrincName, AuthnLevel, + AuthnSvc, AuthIdentity, AuthzSvc); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcBindingSetAuthInfoExA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoExA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, + ULONG AuthnLevel, ULONG AuthnSvc, + RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr, + RPC_SECURITY_QOS *SecurityQos ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + SECURITY_STATUS r; + CredHandle cred; + TimeStamp exp; + ULONG package_count; + ULONG i; + PSecPkgInfoA packages; + ULONG cbMaxToken; + + TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_a((const char*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + + if (SecurityQos) + { + RPC_STATUS status; + + TRACE("SecurityQos { Version=%ld, Capabilties=0x%lx, IdentityTracking=%ld, ImpersonationLevel=%ld", + SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType); + if (SecurityQos->Version >= 2) + { + const RPC_SECURITY_QOS_V2_A *SecurityQos2 = (const RPC_SECURITY_QOS_V2_A *)SecurityQos; + TRACE(", AdditionalSecurityInfoType=%ld", SecurityQos2->AdditionalSecurityInfoType); + if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + TRACE(", { %p, 0x%lx, %ld, %ld, %p, %s }", + SecurityQos2->u.HttpCredentials->TransportCredentials, + SecurityQos2->u.HttpCredentials->Flags, + SecurityQos2->u.HttpCredentials->AuthenticationTarget, + SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes, + SecurityQos2->u.HttpCredentials->AuthnSchemes, + SecurityQos2->u.HttpCredentials->ServerCertificateSubject); + } + TRACE("}\n"); + status = RpcQualityOfService_Create(SecurityQos, FALSE, &bind->QOS); + if (status != RPC_S_OK) + return status; + } + else + { + if (bind->QOS) RpcQualityOfService_Release(bind->QOS); + bind->QOS = NULL; + } + + if (AuthnSvc == RPC_C_AUTHN_DEFAULT) + AuthnSvc = RPC_C_AUTHN_WINNT; + + /* FIXME: the mapping should probably be retrieved using SSPI somehow */ + if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT) + AuthnLevel = RPC_C_AUTHN_LEVEL_NONE; + + if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE)) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + return RPC_S_OK; + } + + if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + { + FIXME("unknown AuthnLevel %u\n", AuthnLevel); + return RPC_S_UNKNOWN_AUTHN_LEVEL; + } + + if (AuthzSvr) + { + FIXME("unsupported AuthzSvr %u\n", AuthzSvr); + return RPC_S_UNKNOWN_AUTHZ_SERVICE; + } + + r = EnumerateSecurityPackagesA(&package_count, &packages); + if (r != SEC_E_OK) + { + ERR("EnumerateSecurityPackagesA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } + + for (i = 0; i < package_count; i++) + if (packages[i].wRPCID == AuthnSvc) + break; + + if (i == package_count) + { + FIXME("unsupported AuthnSvc %u\n", AuthnSvc); + FreeContextBuffer(packages); + return RPC_S_UNKNOWN_AUTHN_SERVICE; + } + + TRACE("found package %s for service %u\n", packages[i].Name, AuthnSvc); + r = AcquireCredentialsHandleA((SEC_CHAR *)ServerPrincName, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL, + AuthIdentity, NULL, NULL, &cred, &exp); + cbMaxToken = packages[i].cbMaxToken; + FreeContextBuffer(packages); + if (r == ERROR_SUCCESS) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken, + AuthIdentity, &bind->AuthInfo); + if (r != RPC_S_OK) + FreeCredentialsHandle(&cred); + return RPC_S_OK; + } + else + { + ERR("AcquireCredentialsHandleA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } +} + +/*********************************************************************** + * RpcBindingSetAuthInfoExW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoExW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel, + ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr, + RPC_SECURITY_QOS *SecurityQos ) +{ + RpcBinding* bind = (RpcBinding*)Binding; + SECURITY_STATUS r; + CredHandle cred; + TimeStamp exp; + ULONG package_count; + ULONG i; + PSecPkgInfoW packages; + ULONG cbMaxToken; + + TRACE("%p %s %u %u %p %u %p\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, SecurityQos); + + if (SecurityQos) + { + RPC_STATUS status; + + TRACE("SecurityQos { Version=%ld, Capabilties=0x%lx, IdentityTracking=%ld, ImpersonationLevel=%ld", + SecurityQos->Version, SecurityQos->Capabilities, SecurityQos->IdentityTracking, SecurityQos->ImpersonationType); + if (SecurityQos->Version >= 2) + { + const RPC_SECURITY_QOS_V2_W *SecurityQos2 = (const RPC_SECURITY_QOS_V2_W *)SecurityQos; + TRACE(", AdditionalSecurityInfoType=%ld", SecurityQos2->AdditionalSecurityInfoType); + if (SecurityQos2->AdditionalSecurityInfoType == RPC_C_AUTHN_INFO_TYPE_HTTP) + TRACE(", { %p, 0x%lx, %ld, %ld, %p, %s }", + SecurityQos2->u.HttpCredentials->TransportCredentials, + SecurityQos2->u.HttpCredentials->Flags, + SecurityQos2->u.HttpCredentials->AuthenticationTarget, + SecurityQos2->u.HttpCredentials->NumberOfAuthnSchemes, + SecurityQos2->u.HttpCredentials->AuthnSchemes, + debugstr_w(SecurityQos2->u.HttpCredentials->ServerCertificateSubject)); + } + TRACE("}\n"); + status = RpcQualityOfService_Create(SecurityQos, TRUE, &bind->QOS); + if (status != RPC_S_OK) + return status; + } + else + { + if (bind->QOS) RpcQualityOfService_Release(bind->QOS); + bind->QOS = NULL; + } + + if (AuthnSvc == RPC_C_AUTHN_DEFAULT) + AuthnSvc = RPC_C_AUTHN_WINNT; + + /* FIXME: the mapping should probably be retrieved using SSPI somehow */ + if (AuthnLevel == RPC_C_AUTHN_LEVEL_DEFAULT) + AuthnLevel = RPC_C_AUTHN_LEVEL_NONE; + + if ((AuthnLevel == RPC_C_AUTHN_LEVEL_NONE) || (AuthnSvc == RPC_C_AUTHN_NONE)) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + return RPC_S_OK; + } + + if (AuthnLevel > RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + { + FIXME("unknown AuthnLevel %u\n", AuthnLevel); + return RPC_S_UNKNOWN_AUTHN_LEVEL; + } + + if (AuthzSvr) + { + FIXME("unsupported AuthzSvr %u\n", AuthzSvr); + return RPC_S_UNKNOWN_AUTHZ_SERVICE; + } + + r = EnumerateSecurityPackagesW(&package_count, &packages); + if (r != SEC_E_OK) + { + ERR("EnumerateSecurityPackagesA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } + + for (i = 0; i < package_count; i++) + if (packages[i].wRPCID == AuthnSvc) + break; + + if (i == package_count) + { + FIXME("unsupported AuthnSvc %u\n", AuthnSvc); + FreeContextBuffer(packages); + return RPC_S_UNKNOWN_AUTHN_SERVICE; + } + + TRACE("found package %s for service %u\n", debugstr_w(packages[i].Name), AuthnSvc); + r = AcquireCredentialsHandleW((SEC_WCHAR *)ServerPrincName, packages[i].Name, SECPKG_CRED_OUTBOUND, NULL, + AuthIdentity, NULL, NULL, &cred, &exp); + cbMaxToken = packages[i].cbMaxToken; + FreeContextBuffer(packages); + if (r == ERROR_SUCCESS) + { + if (bind->AuthInfo) RpcAuthInfo_Release(bind->AuthInfo); + bind->AuthInfo = NULL; + r = RpcAuthInfo_Create(AuthnLevel, AuthnSvc, cred, exp, cbMaxToken, + AuthIdentity, &bind->AuthInfo); + if (r != RPC_S_OK) + FreeCredentialsHandle(&cred); + return RPC_S_OK; + } + else + { + ERR("AcquireCredentialsHandleA failed with error 0x%08x\n", r); + return RPC_S_SEC_PKG_ERROR; + } +} + +/*********************************************************************** + * RpcBindingSetAuthInfoA (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoA( RPC_BINDING_HANDLE Binding, RPC_CSTR ServerPrincName, ULONG AuthnLevel, + ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr ) +{ + TRACE("%p %s %u %u %p %u\n", Binding, debugstr_a((const char*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr); + return RpcBindingSetAuthInfoExA(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL); +} + +/*********************************************************************** + * RpcBindingSetAuthInfoW (RPCRT4.@) + */ +RPCRTAPI RPC_STATUS RPC_ENTRY +RpcBindingSetAuthInfoW( RPC_BINDING_HANDLE Binding, RPC_WSTR ServerPrincName, ULONG AuthnLevel, + ULONG AuthnSvc, RPC_AUTH_IDENTITY_HANDLE AuthIdentity, ULONG AuthzSvr ) +{ + TRACE("%p %s %u %u %p %u\n", Binding, debugstr_w((const WCHAR*)ServerPrincName), + AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr); + return RpcBindingSetAuthInfoExW(Binding, ServerPrincName, AuthnLevel, AuthnSvc, AuthIdentity, AuthzSvr, NULL); +} + +/*********************************************************************** + * RpcBindingSetOption (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcBindingSetOption(RPC_BINDING_HANDLE BindingHandle, ULONG Option, ULONG OptionValue) +{ + FIXME("(%p, %d, %d): stub\n", BindingHandle, Option, OptionValue); + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4_new/rpc_binding.h b/reactos/dll/win32/rpcrt4_new/rpc_binding.h new file mode 100644 index 00000000000..5113b27e358 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_binding.h @@ -0,0 +1,201 @@ +/* + * RPC binding API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + */ + +#ifndef __WINE_RPC_BINDING_H +#define __WINE_RPC_BINDING_H + +#include "wine/rpcss_shared.h" +#include "security.h" +#include "wine/list.h" + + +typedef struct _RpcAuthInfo +{ + LONG refs; + + ULONG AuthnLevel; + ULONG AuthnSvc; + CredHandle cred; + TimeStamp exp; + ULONG cbMaxToken; + /* the auth identity pointer that the application passed us (freed by application) */ + RPC_AUTH_IDENTITY_HANDLE *identity; + /* our copy of NT auth identity structure, if the authentication service + * takes an NT auth identity */ + SEC_WINNT_AUTH_IDENTITY_W *nt_identity; +} RpcAuthInfo; + +typedef struct _RpcQualityOfService +{ + LONG refs; + + RPC_SECURITY_QOS_V2_W *qos; +} RpcQualityOfService; + +typedef struct _RpcAssoc +{ + struct list entry; /* entry in the global list of associations */ + LONG refs; + + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + LPWSTR NetworkOptions; + + /* id of this association group */ + ULONG assoc_group_id; + + CRITICAL_SECTION cs; + struct list connection_pool; +} RpcAssoc; + +struct connection_ops; + +typedef struct _RpcConnection +{ + struct _RpcConnection* Next; + BOOL server; + LPSTR NetworkAddr; + LPSTR Endpoint; + LPWSTR NetworkOptions; + const struct connection_ops *ops; + USHORT MaxTransmissionSize; + /* The active interface bound to server. */ + RPC_SYNTAX_IDENTIFIER ActiveInterface; + USHORT NextCallId; + + /* authentication */ + CtxtHandle ctx; + TimeStamp exp; + ULONG attr; + RpcAuthInfo *AuthInfo; + ULONG encryption_auth_len; + ULONG signature_auth_len; + RpcQualityOfService *QOS; + + /* client-only */ + struct list conn_pool_entry; + ULONG assoc_group_id; /* association group returned during binding */ +} RpcConnection; + +struct connection_ops { + const char *name; + unsigned char epm_protocols[2]; /* only floors 3 and 4. see http://www.opengroup.org/onlinepubs/9629399/apdxl.htm */ + RpcConnection *(*alloc)(void); + RPC_STATUS (*open_connection_client)(RpcConnection *conn); + RPC_STATUS (*handoff)(RpcConnection *old_conn, RpcConnection *new_conn); + int (*read)(RpcConnection *conn, void *buffer, unsigned int len); + int (*write)(RpcConnection *conn, const void *buffer, unsigned int len); + int (*close)(RpcConnection *conn); + size_t (*get_top_of_tower)(unsigned char *tower_data, const char *networkaddr, const char *endpoint); + RPC_STATUS (*parse_top_of_tower)(const unsigned char *tower_data, size_t tower_size, char **networkaddr, char **endpoint); +}; + +/* don't know what MS's structure looks like */ +typedef struct _RpcBinding +{ + LONG refs; + struct _RpcBinding* Next; + BOOL server; + UUID ObjectUuid; + LPSTR Protseq; + LPSTR NetworkAddr; + LPSTR Endpoint; + LPWSTR NetworkOptions; + RPC_BLOCKING_FN BlockingFn; + ULONG ServerTid; + RpcConnection* FromConn; + RpcAssoc *Assoc; + + /* authentication */ + RpcAuthInfo *AuthInfo; + RpcQualityOfService *QOS; +} RpcBinding; + +LPSTR RPCRT4_strndupA(LPCSTR src, INT len); +LPWSTR RPCRT4_strndupW(LPCWSTR src, INT len); +LPSTR RPCRT4_strdupWtoA(LPCWSTR src); +LPWSTR RPCRT4_strdupAtoW(LPCSTR src); +void RPCRT4_strfree(LPSTR src); + +#define RPCRT4_strdupA(x) RPCRT4_strndupA((x),-1) +#define RPCRT4_strdupW(x) RPCRT4_strndupW((x),-1) + +ULONG RpcAuthInfo_AddRef(RpcAuthInfo *AuthInfo); +ULONG RpcAuthInfo_Release(RpcAuthInfo *AuthInfo); +BOOL RpcAuthInfo_IsEqual(const RpcAuthInfo *AuthInfo1, const RpcAuthInfo *AuthInfo2); +ULONG RpcQualityOfService_AddRef(RpcQualityOfService *qos); +ULONG RpcQualityOfService_Release(RpcQualityOfService *qos); +BOOL RpcQualityOfService_IsEqual(const RpcQualityOfService *qos1, const RpcQualityOfService *qos2); + +RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAssoc **assoc); +RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, const RPC_SYNTAX_IDENTIFIER *InterfaceId, const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, RpcQualityOfService *QOS, RpcConnection **Connection); +void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection); +ULONG RpcAssoc_Release(RpcAssoc *assoc); + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS); +RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_OpenClientConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection); +RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection); + +RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPCSTR Endpoint); +RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, const UUID* ObjectUuid); +RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection); +RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding); +RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding); +RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection, PRPC_SYNTAX_IDENTIFIER TransferSyntax, PRPC_SYNTAX_IDENTIFIER InterfaceId); +RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection); +BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply); +HANDLE RPCRT4_GetMasterMutex(void); +HANDLE RPCRT4_RpcssNPConnect(void); + +static inline const char *rpcrt4_conn_get_name(RpcConnection *Connection) +{ + return Connection->ops->name; +} + +static inline int rpcrt4_conn_read(RpcConnection *Connection, + void *buffer, unsigned int len) +{ + return Connection->ops->read(Connection, buffer, len); +} + +static inline int rpcrt4_conn_write(RpcConnection *Connection, + const void *buffer, unsigned int len) +{ + return Connection->ops->write(Connection, buffer, len); +} + +static inline int rpcrt4_conn_close(RpcConnection *Connection) +{ + return Connection->ops->close(Connection); +} + +static inline RPC_STATUS rpcrt4_conn_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + return old_conn->ops->handoff(old_conn, new_conn); +} + +/* floors 3 and up */ +RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, size_t *tower_size, const char *protseq, const char *networkaddr, const char *endpoint); +RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, size_t tower_size, char **protseq, char **networkaddr, char **endpoint); + +#endif diff --git a/reactos/dll/win32/rpcrt4_new/rpc_defs.h b/reactos/dll/win32/rpcrt4_new/rpc_defs.h new file mode 100644 index 00000000000..7499dcd1c1d --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_defs.h @@ -0,0 +1,196 @@ +/* + * RPC definitions + * + * Copyright 2001-2002 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * 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 + */ + +#ifndef __WINE_RPC_DEFS_H +#define __WINE_RPC_DEFS_H + +/* info from http://www.microsoft.com/msj/0398/dcomtextfigs.htm */ + +typedef struct +{ + unsigned char rpc_ver; /* RPC major version (5) */ + unsigned char rpc_ver_minor; /* RPC minor version (0) */ + unsigned char ptype; /* Packet type (PKT_*) */ + unsigned char flags; + unsigned char drep[4]; /* Data representation */ + unsigned short frag_len; /* Data size in bytes including header and tail. */ + unsigned short auth_len; /* Authentication length */ + unsigned long call_id; /* Call identifier. */ +} RpcPktCommonHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned short opnum; +} RpcPktRequestHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char cancel_count; + unsigned char reserved; +} RpcPktResponseHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned long alloc_hint; /* Data size in bytes excluding header and tail. */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char cancel_count; /* Received cancel count */ + unsigned char reserved; /* Force alignment! */ + unsigned long status; /* Runtime fault code (RPC_STATUS) */ + unsigned long reserved2; +} RpcPktFaultHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short max_tsize; /* Maximum transmission fragment size */ + unsigned short max_rsize; /* Maximum receive fragment size */ + unsigned long assoc_gid; /* Associated group id */ + unsigned char num_elements; /* Number of elements */ + unsigned char padding[3]; /* Force alignment! */ + unsigned short context_id; /* Presentation context identifier */ + unsigned char num_syntaxes; /* Number of syntaxes */ + RPC_SYNTAX_IDENTIFIER abstract; + RPC_SYNTAX_IDENTIFIER transfer; +} RpcPktBindHdr; + +#include "pshpack1.h" +typedef struct +{ + unsigned short length; /* Length of the string including null terminator */ + char string[1]; /* String data in single byte, null terminated form */ +} RpcAddressString; +#include "poppack.h" + +typedef struct +{ + unsigned char num_results; /* Number of results */ + unsigned char reserved[3]; /* Force alignment! */ + struct { + unsigned short result; + unsigned short reason; + } results[1]; +} RpcResults; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short max_tsize; /* Maximum transmission fragment size */ + unsigned short max_rsize; /* Maximum receive fragment size */ + unsigned long assoc_gid; /* Associated group id */ + /* + * Following this header are these fields: + * RpcAddressString server_address; + * [0 - 3 bytes of padding so that results is 4-byte aligned] + * RpcResults results; + * RPC_SYNTAX_IDENTIFIER transfer; + */ +} RpcPktBindAckHdr; + +typedef struct +{ + RpcPktCommonHdr common; + unsigned short reject_reason; + unsigned char protocols_count; + struct { + unsigned char rpc_ver; + unsigned char rpc_ver_minor; + } protocols[1]; +} RpcPktBindNAckHdr; + +/* Union representing all possible packet headers */ +typedef union +{ + RpcPktCommonHdr common; + RpcPktRequestHdr request; + RpcPktResponseHdr response; + RpcPktFaultHdr fault; + RpcPktBindHdr bind; + RpcPktBindAckHdr bind_ack; + RpcPktBindNAckHdr bind_nack; +} RpcPktHdr; + +typedef struct +{ + unsigned char auth_type; /* authentication scheme in use */ + unsigned char auth_level; /* RPC_C_AUTHN_LEVEL* */ + unsigned char auth_pad_length; /* length of padding to restore n % 4 alignment */ + unsigned char auth_reserved; /* reserved, must be zero */ + unsigned long auth_context_id; /* unique value for the authenticated connection */ +} RpcAuthVerifier; + +#define RPC_AUTH_VERIFIER_LEN(common_hdr) \ + ((common_hdr)->auth_len ? (common_hdr)->auth_len + sizeof(RpcAuthVerifier) : 0) + +#define RPC_VER_MAJOR 5 +#define RPC_VER_MINOR 0 + +#define RPC_FLG_FIRST 1 +#define RPC_FLG_LAST 2 +#define RPC_FLG_OBJECT_UUID 0x80 + +#define RPC_MIN_PACKET_SIZE 0x1000 +#define RPC_MAX_PACKET_SIZE 0x16D0 + +#define PKT_REQUEST 0 +#define PKT_PING 1 +#define PKT_RESPONSE 2 +#define PKT_FAULT 3 +#define PKT_WORKING 4 +#define PKT_NOCALL 5 +#define PKT_REJECT 6 +#define PKT_ACK 7 +#define PKT_CL_CANCEL 8 +#define PKT_FACK 9 +#define PKT_CANCEL_ACK 10 +#define PKT_BIND 11 +#define PKT_BIND_ACK 12 +#define PKT_BIND_NACK 13 +#define PKT_ALTER_CONTEXT 14 +#define PKT_ALTER_CONTEXT_RESP 15 +#define PKT_AUTH3 16 +#define PKT_SHUTDOWN 17 +#define PKT_CO_CANCEL 18 +#define PKT_ORPHANED 19 + +#define RESULT_ACCEPT 0 + +#define NO_REASON 0 + +#define NCADG_IP_UDP 0x08 +#define NCACN_IP_TCP 0x07 +#define NCADG_IPX 0x0E +#define NCACN_SPX 0x0C +#define NCACN_NB_NB 0x12 +#define NCACN_NB_IPX 0x0D +#define NCACN_DNET_NSP 0x04 +#define NCACN_HTTP 0x1F + +/* FreeDCE: TWR_C_FLR_PROT_ID_IP */ +#define TWR_IP 0x09 + +#endif /* __WINE_RPC_DEFS_H */ diff --git a/reactos/dll/win32/rpcrt4_new/rpc_epmap.c b/reactos/dll/win32/rpcrt4_new/rpc_epmap.c new file mode 100644 index 00000000000..cac3f626c1a --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_epmap.c @@ -0,0 +1,384 @@ +/* + * RPC endpoint mapper + * + * Copyright 2002 Greg Turner + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + * + * TODO: + * - actually do things right + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "rpc.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "epm_towers.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +/* The "real" RPC portmapper endpoints that I know of are: + * + * ncadg_ip_udp: 135 + * ncacn_ip_tcp: 135 + * ncacn_np: \\pipe\epmapper (?) + * ncalrpc: epmapper + * + * If the user's machine ran a DCE RPC daemon, it would + * probably be possible to connect to it, but there are many + * reasons not to, like: + * - the user probably does *not* run one, and probably + * shouldn't be forced to run one just for local COM + * - very few Unix systems use DCE RPC... if they run a RPC + * daemon at all, it's usually Sun RPC + * - DCE RPC registrations are persistent and saved on disk, + * while MS-RPC registrations are documented as non-persistent + * and stored only in RAM, and auto-destroyed when the process + * dies (something DCE RPC can't do) + * + * Of course, if the user *did* want to run a DCE RPC daemon anyway, + * there would be interoperability advantages, like the possibility + * of running a fully functional DCOM server using Wine... + */ + +/*********************************************************************** + * RpcEpRegisterA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpRegisterA( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, + UUID_VECTOR *UuidVector, RPC_CSTR Annotation ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p,%s)\n", IfSpec, BindingVector, UuidVector, debugstr_a((char*)Annotation)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; cCount; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; cCount; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* FIXME: Do something with annotation. */ + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_REGISTEREPMSG; + msg.message.registerepmsg.iface = If->InterfaceId; + msg.message.registerepmsg.no_replace = 0; + + msg.message.registerepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.registerepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.registerepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.registerepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.registerepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpUnregister (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpUnregister( RPC_IF_HANDLE IfSpec, RPC_BINDING_VECTOR *BindingVector, + UUID_VECTOR *UuidVector ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + char *vardata_payload, *vp; + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + unsigned long c; + RPC_STATUS rslt = RPC_S_OK; + + TRACE("(%p,%p,%p)\n", IfSpec, BindingVector, UuidVector); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + for (c=0; cCount; c++) { + RpcBinding* bind = (RpcBinding*)(BindingVector->BindingH[c]); + TRACE(" protseq[%ld]=%s\n", c, debugstr_a(bind->Protseq)); + TRACE(" endpoint[%ld]=%s\n", c, debugstr_a(bind->Endpoint)); + } + if (UuidVector) { + for (c=0; cCount; c++) + TRACE(" obj[%ld]=%s\n", c, debugstr_guid(UuidVector->Uuid[c])); + } + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_UNREGISTEREPMSG; + msg.message.unregisterepmsg.iface = If->InterfaceId; + + msg.message.unregisterepmsg.object_count = (UuidVector) ? UuidVector->Count : 0; + msg.message.unregisterepmsg.binding_count = BindingVector->Count; + + /* calculate vardata payload size */ + msg.vardata_payload_size = msg.message.unregisterepmsg.object_count * sizeof(UUID); + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding *)(BindingVector->BindingH[c]); + msg.vardata_payload_size += strlen(bind->Protseq) + 1; + msg.vardata_payload_size += strlen(bind->Endpoint) + 1; + } + + /* allocate the payload buffer */ + vp = vardata_payload = LocalAlloc(LPTR, msg.vardata_payload_size); + if (!vardata_payload) + return RPC_S_OUT_OF_MEMORY; + + /* populate the payload data */ + for (c=0; c < msg.message.unregisterepmsg.object_count; c++) { + CopyMemory(vp, UuidVector->Uuid[c], sizeof(UUID)); + vp += sizeof(UUID); + } + + for (c=0; c < msg.message.unregisterepmsg.binding_count; c++) { + RpcBinding *bind = (RpcBinding*)(BindingVector->BindingH[c]); + unsigned long pslen = strlen(bind->Protseq) + 1, eplen = strlen(bind->Endpoint) + 1; + CopyMemory(vp, bind->Protseq, pslen); + vp += pslen; + CopyMemory(vp, bind->Endpoint, eplen); + vp += eplen; + } + + /* send our request */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, vardata_payload, &reply)) + rslt = RPC_S_OUT_OF_MEMORY; + + /* free the payload buffer */ + LocalFree(vardata_payload); + + return rslt; +} + +/*********************************************************************** + * RpcEpResolveBinding (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcEpResolveBinding( RPC_BINDING_HANDLE Binding, RPC_IF_HANDLE IfSpec ) +{ + RPCSS_NP_MESSAGE msg; + RPCSS_NP_REPLY reply; + PRPC_CLIENT_INTERFACE If = (PRPC_CLIENT_INTERFACE)IfSpec; + RpcBinding* bind = (RpcBinding*)Binding; + + TRACE("(%p,%p)\n", Binding, IfSpec); + TRACE(" protseq=%s\n", debugstr_a(bind->Protseq)); + TRACE(" obj=%s\n", debugstr_guid(&bind->ObjectUuid)); + TRACE(" ifid=%s\n", debugstr_guid(&If->InterfaceId.SyntaxGUID)); + + /* FIXME: totally untested */ + + /* just return for fully bound handles */ + if (bind->Endpoint && (bind->Endpoint[0] != '\0')) + return RPC_S_OK; + + /* construct the message to rpcss */ + msg.message_type = RPCSS_NP_MESSAGE_TYPEID_RESOLVEEPMSG; + msg.message.resolveepmsg.iface = If->InterfaceId; + msg.message.resolveepmsg.object = bind->ObjectUuid; + + msg.vardata_payload_size = strlen(bind->Protseq) + 1; + + /* send the message */ + if (!RPCRT4_RPCSSOnDemandCall(&msg, bind->Protseq, &reply)) + return RPC_S_OUT_OF_MEMORY; + + /* empty-string result means not registered */ + if (reply.as_string[0] == '\0') + return EPT_S_NOT_REGISTERED; + + /* otherwise we fully bind the handle & return RPC_S_OK */ + return RPCRT4_ResolveBinding(Binding, reply.as_string); +} + +typedef unsigned int unsigned32; +typedef struct twr_t + { + unsigned32 tower_length; + /* [size_is] */ BYTE tower_octet_string[ 1 ]; + } twr_t; + +/*********************************************************************** + * TowerExplode (RPCRT4.@) + */ +RPC_STATUS WINAPI TowerExplode( + const twr_t *tower, PRPC_SYNTAX_IDENTIFIER object, PRPC_SYNTAX_IDENTIFIER syntax, + char **protseq, char **endpoint, char **address) +{ + size_t tower_size; + RPC_STATUS status; + const unsigned char *p; + u_int16 floor_count; + const twr_uuid_floor_t *object_floor; + const twr_uuid_floor_t *syntax_floor; + + if (protseq) + *protseq = NULL; + if (endpoint) + *endpoint = NULL; + if (address) + *address = NULL; + + tower_size = tower->tower_length; + + if (tower_size < sizeof(u_int16)) + return EPT_S_NOT_REGISTERED; + + p = &tower->tower_octet_string[0]; + + floor_count = *(const u_int16 *)p; + p += sizeof(u_int16); + tower_size -= sizeof(u_int16); + TRACE("floor_count: %d\n", floor_count); + /* FIXME: should we do something with the floor count? at the moment we don't */ + + if (tower_size < sizeof(*object_floor) + sizeof(*syntax_floor)) + return EPT_S_NOT_REGISTERED; + + object_floor = (const twr_uuid_floor_t *)p; + p += sizeof(*object_floor); + tower_size -= sizeof(*object_floor); + syntax_floor = (const twr_uuid_floor_t *)p; + p += sizeof(*syntax_floor); + tower_size -= sizeof(*syntax_floor); + + if ((object_floor->count_lhs != sizeof(object_floor->protid) + + sizeof(object_floor->uuid) + sizeof(object_floor->major_version)) || + (object_floor->protid != EPM_PROTOCOL_UUID) || + (object_floor->count_rhs != sizeof(object_floor->minor_version))) + return EPT_S_NOT_REGISTERED; + + if ((syntax_floor->count_lhs != sizeof(syntax_floor->protid) + + sizeof(syntax_floor->uuid) + sizeof(syntax_floor->major_version)) || + (syntax_floor->protid != EPM_PROTOCOL_UUID) || + (syntax_floor->count_rhs != sizeof(syntax_floor->minor_version))) + return EPT_S_NOT_REGISTERED; + + status = RpcTransport_ParseTopOfTower(p, tower_size, protseq, address, endpoint); + if ((status == RPC_S_OK) && syntax && object) + { + syntax->SyntaxGUID = syntax_floor->uuid; + syntax->SyntaxVersion.MajorVersion = syntax_floor->major_version; + syntax->SyntaxVersion.MinorVersion = syntax_floor->minor_version; + object->SyntaxGUID = object_floor->uuid; + object->SyntaxVersion.MajorVersion = object_floor->major_version; + object->SyntaxVersion.MinorVersion = object_floor->minor_version; + } + return status; +} + +/*********************************************************************** + * TowerConstruct (RPCRT4.@) + */ +RPC_STATUS WINAPI TowerConstruct( + const RPC_SYNTAX_IDENTIFIER *object, const RPC_SYNTAX_IDENTIFIER *syntax, + const char *protseq, const char *endpoint, const char *address, + twr_t **tower) +{ + size_t tower_size; + RPC_STATUS status; + unsigned char *p; + twr_uuid_floor_t *object_floor; + twr_uuid_floor_t *syntax_floor; + + *tower = NULL; + + status = RpcTransport_GetTopOfTower(NULL, &tower_size, protseq, address, endpoint); + + if (status != RPC_S_OK) + return status; + + tower_size += sizeof(u_int16) + sizeof(*object_floor) + sizeof(*syntax_floor); + *tower = I_RpcAllocate(FIELD_OFFSET(twr_t, tower_octet_string[tower_size])); + if (!*tower) + return RPC_S_OUT_OF_RESOURCES; + + (*tower)->tower_length = tower_size; + p = &(*tower)->tower_octet_string[0]; + *(u_int16 *)p = 5; /* number of floors */ + p += sizeof(u_int16); + object_floor = (twr_uuid_floor_t *)p; + p += sizeof(*object_floor); + syntax_floor = (twr_uuid_floor_t *)p; + p += sizeof(*syntax_floor); + + object_floor->count_lhs = sizeof(object_floor->protid) + sizeof(object_floor->uuid) + + sizeof(object_floor->major_version); + object_floor->protid = EPM_PROTOCOL_UUID; + object_floor->count_rhs = sizeof(object_floor->minor_version); + object_floor->uuid = object->SyntaxGUID; + object_floor->major_version = object->SyntaxVersion.MajorVersion; + object_floor->minor_version = object->SyntaxVersion.MinorVersion; + + syntax_floor->count_lhs = sizeof(syntax_floor->protid) + sizeof(syntax_floor->uuid) + + sizeof(syntax_floor->major_version); + syntax_floor->protid = EPM_PROTOCOL_UUID; + syntax_floor->count_rhs = sizeof(syntax_floor->minor_version); + syntax_floor->uuid = syntax->SyntaxGUID; + syntax_floor->major_version = syntax->SyntaxVersion.MajorVersion; + syntax_floor->minor_version = syntax->SyntaxVersion.MinorVersion; + + status = RpcTransport_GetTopOfTower(p, &tower_size, protseq, address, endpoint); + if (status != RPC_S_OK) + { + I_RpcFree(*tower); + *tower = NULL; + return status; + } + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4_new/rpc_message.c b/reactos/dll/win32/rpcrt4_new/rpc_message.c new file mode 100644 index 00000000000..bfd5aece881 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_message.c @@ -0,0 +1,1138 @@ +/* + * RPC messages + * + * Copyright 2001-2002 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * Copyright 2006 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 + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "rpc.h" +#include "rpcndr.h" +#include "rpcdcep.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_defs.h" +#include "rpc_message.h" +#include "ncastatus.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +/* note: the DCE/RPC spec says the alignment amount should be 4, but + * MS/RPC servers seem to always use 16 */ +#define AUTH_ALIGNMENT 16 + +/* gets the amount needed to round a value up to the specified alignment */ +#define ROUND_UP_AMOUNT(value, alignment) \ + (((alignment) - (((value) % (alignment)))) % (alignment)) +#define ROUND_UP(value, alignment) (((value) + ((alignment) - 1)) & ~((alignment)-1)) + +enum secure_packet_direction +{ + SECURE_PACKET_SEND, + SECURE_PACKET_RECEIVE +}; + +static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg); + +static DWORD RPCRT4_GetHeaderSize(const RpcPktHdr *Header) +{ + static const DWORD header_sizes[] = { + sizeof(Header->request), 0, sizeof(Header->response), + sizeof(Header->fault), 0, 0, 0, 0, 0, 0, 0, sizeof(Header->bind), + sizeof(Header->bind_ack), sizeof(Header->bind_nack), + 0, 0, 0, 0, 0 + }; + ULONG ret = 0; + + if (Header->common.ptype < sizeof(header_sizes) / sizeof(header_sizes[0])) { + ret = header_sizes[Header->common.ptype]; + if (ret == 0) + FIXME("unhandled packet type\n"); + if (Header->common.flags & RPC_FLG_OBJECT_UUID) + ret += sizeof(UUID); + } else { + TRACE("invalid packet type\n"); + } + + return ret; +} + +static int packet_has_body(const RpcPktHdr *Header) +{ + return (Header->common.ptype == PKT_FAULT) || + (Header->common.ptype == PKT_REQUEST) || + (Header->common.ptype == PKT_RESPONSE); +} + +static int packet_has_auth_verifier(const RpcPktHdr *Header) +{ + return !(Header->common.ptype == PKT_BIND_NACK) && + !(Header->common.ptype == PKT_SHUTDOWN); +} + +static VOID RPCRT4_BuildCommonHeader(RpcPktHdr *Header, unsigned char PacketType, + unsigned long DataRepresentation) +{ + Header->common.rpc_ver = RPC_VER_MAJOR; + Header->common.rpc_ver_minor = RPC_VER_MINOR; + Header->common.ptype = PacketType; + Header->common.drep[0] = LOBYTE(LOWORD(DataRepresentation)); + Header->common.drep[1] = HIBYTE(LOWORD(DataRepresentation)); + Header->common.drep[2] = LOBYTE(HIWORD(DataRepresentation)); + Header->common.drep[3] = HIBYTE(HIWORD(DataRepresentation)); + Header->common.auth_len = 0; + Header->common.call_id = 1; + Header->common.flags = 0; + /* Flags and fragment length are computed in RPCRT4_Send. */ +} + +static RpcPktHdr *RPCRT4_BuildRequestHeader(unsigned long DataRepresentation, + unsigned long BufferLength, + unsigned short ProcNum, + UUID *ObjectUuid) +{ + RpcPktHdr *header; + BOOL has_object; + RPC_STATUS status; + + has_object = (ObjectUuid != NULL && !UuidIsNil(ObjectUuid, &status)); + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(header->request) + (has_object ? sizeof(UUID) : 0)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_REQUEST, DataRepresentation); + header->common.frag_len = sizeof(header->request); + header->request.alloc_hint = BufferLength; + header->request.context_id = 0; + header->request.opnum = ProcNum; + if (has_object) { + header->common.flags |= RPC_FLG_OBJECT_UUID; + header->common.frag_len += sizeof(UUID); + memcpy(&header->request + 1, ObjectUuid, sizeof(UUID)); + } + + return header; +} + +RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, + unsigned long BufferLength) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->response)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_RESPONSE, DataRepresentation); + header->common.frag_len = sizeof(header->response); + header->response.alloc_hint = BufferLength; + + return header; +} + +RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, + RPC_STATUS Status) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->fault)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_FAULT, DataRepresentation); + header->common.frag_len = sizeof(header->fault); + header->fault.status = Status; + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, + unsigned short MaxTransmissionSize, + unsigned short MaxReceiveSize, + unsigned long AssocGroupId, + const RPC_SYNTAX_IDENTIFIER *AbstractId, + const RPC_SYNTAX_IDENTIFIER *TransferId) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND, DataRepresentation); + header->common.frag_len = sizeof(header->bind); + header->bind.max_tsize = MaxTransmissionSize; + header->bind.max_rsize = MaxReceiveSize; + header->bind.assoc_gid = AssocGroupId; + header->bind.num_elements = 1; + header->bind.num_syntaxes = 1; + memcpy(&header->bind.abstract, AbstractId, sizeof(RPC_SYNTAX_IDENTIFIER)); + memcpy(&header->bind.transfer, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); + + return header; +} + +static RpcPktHdr *RPCRT4_BuildAuthHeader(unsigned long DataRepresentation) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(header->common) + 12); + if (header == NULL) + return NULL; + + RPCRT4_BuildCommonHeader(header, PKT_AUTH3, DataRepresentation); + header->common.frag_len = 0x14; + header->common.auth_len = 0; + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, + unsigned char RpcVersion, + unsigned char RpcVersionMinor) +{ + RpcPktHdr *header; + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(header->bind_nack)); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND_NACK, DataRepresentation); + header->common.frag_len = sizeof(header->bind_nack); + header->bind_nack.protocols_count = 1; + header->bind_nack.protocols[0].rpc_ver = RpcVersion; + header->bind_nack.protocols[0].rpc_ver_minor = RpcVersionMinor; + + return header; +} + +RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, + unsigned short MaxTransmissionSize, + unsigned short MaxReceiveSize, + LPCSTR ServerAddress, + unsigned long Result, + unsigned long Reason, + const RPC_SYNTAX_IDENTIFIER *TransferId) +{ + RpcPktHdr *header; + unsigned long header_size; + RpcAddressString *server_address; + RpcResults *results; + RPC_SYNTAX_IDENTIFIER *transfer_id; + + header_size = sizeof(header->bind_ack) + + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[strlen(ServerAddress) + 1]), 4) + + sizeof(RpcResults) + + sizeof(RPC_SYNTAX_IDENTIFIER); + + header = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, header_size); + if (header == NULL) { + return NULL; + } + + RPCRT4_BuildCommonHeader(header, PKT_BIND_ACK, DataRepresentation); + header->common.frag_len = header_size; + header->bind_ack.max_tsize = MaxTransmissionSize; + header->bind_ack.max_rsize = MaxReceiveSize; + server_address = (RpcAddressString*)(&header->bind_ack + 1); + server_address->length = strlen(ServerAddress) + 1; + strcpy(server_address->string, ServerAddress); + /* results is 4-byte aligned */ + results = (RpcResults*)((ULONG_PTR)server_address + ROUND_UP(FIELD_OFFSET(RpcAddressString, string[server_address->length]), 4)); + results->num_results = 1; + results->results[0].result = Result; + results->results[0].reason = Reason; + transfer_id = (RPC_SYNTAX_IDENTIFIER*)(results + 1); + memcpy(transfer_id, TransferId, sizeof(RPC_SYNTAX_IDENTIFIER)); + + return header; +} + +VOID RPCRT4_FreeHeader(RpcPktHdr *Header) +{ + HeapFree(GetProcessHeap(), 0, Header); +} + +NCA_STATUS RPC2NCA_STATUS(RPC_STATUS status) +{ + switch (status) + { + case ERROR_INVALID_HANDLE: return NCA_S_FAULT_CONTEXT_MISMATCH; + case ERROR_OUTOFMEMORY: return NCA_S_FAULT_REMOTE_NO_MEMORY; + case RPC_S_NOT_LISTENING: return NCA_S_SERVER_TOO_BUSY; + case RPC_S_UNKNOWN_IF: return NCA_S_UNK_IF; + case RPC_S_SERVER_TOO_BUSY: return NCA_S_SERVER_TOO_BUSY; + case RPC_S_CALL_FAILED: return NCA_S_FAULT_UNSPEC; + case RPC_S_CALL_FAILED_DNE: return NCA_S_MANAGER_NOT_ENTERED; + case RPC_S_PROTOCOL_ERROR: return NCA_S_PROTO_ERROR; + case RPC_S_UNSUPPORTED_TYPE: return NCA_S_UNSUPPORTED_TYPE; + case RPC_S_INVALID_TAG: return NCA_S_FAULT_INVALID_TAG; + case RPC_S_INVALID_BOUND: return NCA_S_FAULT_INVALID_BOUND; + case RPC_S_PROCNUM_OUT_OF_RANGE: return NCA_S_OP_RNG_ERROR; + case RPC_X_SS_HANDLES_MISMATCH: return NCA_S_FAULT_CONTEXT_MISMATCH; + case STATUS_FLOAT_DIVIDE_BY_ZERO: return NCA_S_FAULT_FP_DIV_ZERO; + case STATUS_FLOAT_INVALID_OPERATION: return NCA_S_FAULT_FP_ERROR; + case STATUS_FLOAT_OVERFLOW: return NCA_S_FAULT_FP_OVERFLOW; + case STATUS_FLOAT_UNDERFLOW: return NCA_S_FAULT_FP_UNDERFLOW; + case STATUS_INTEGER_DIVIDE_BY_ZERO: return NCA_S_FAULT_INT_DIV_BY_ZERO; + case STATUS_INTEGER_OVERFLOW: return NCA_S_FAULT_INT_OVERFLOW; + default: return status; + } +} + +RPC_STATUS NCA2RPC_STATUS(NCA_STATUS status) +{ + switch (status) + { + case NCA_S_COMM_FAILURE: return RPC_S_COMM_FAILURE; + case NCA_S_OP_RNG_ERROR: return RPC_S_PROCNUM_OUT_OF_RANGE; + case NCA_S_UNK_IF: return RPC_S_UNKNOWN_IF; + case NCA_S_YOU_CRASHED: return RPC_S_CALL_FAILED; + case NCA_S_PROTO_ERROR: return RPC_S_PROTOCOL_ERROR; + case NCA_S_OUT_ARGS_TOO_BIG: return ERROR_NOT_ENOUGH_SERVER_MEMORY; + case NCA_S_SERVER_TOO_BUSY: return RPC_S_SERVER_TOO_BUSY; + case NCA_S_UNSUPPORTED_TYPE: return RPC_S_UNSUPPORTED_TYPE; + case NCA_S_FAULT_INT_DIV_BY_ZERO: return RPC_S_ZERO_DIVIDE; + case NCA_S_FAULT_ADDR_ERROR: return RPC_S_ADDRESS_ERROR; + case NCA_S_FAULT_FP_DIV_ZERO: return RPC_S_FP_DIV_ZERO; + case NCA_S_FAULT_FP_UNDERFLOW: return RPC_S_FP_UNDERFLOW; + case NCA_S_FAULT_FP_OVERFLOW: return RPC_S_FP_OVERFLOW; + case NCA_S_FAULT_INVALID_TAG: return RPC_S_INVALID_TAG; + case NCA_S_FAULT_INVALID_BOUND: return RPC_S_INVALID_BOUND; + case NCA_S_RPC_VERSION_MISMATCH: return RPC_S_PROTOCOL_ERROR; + case NCA_S_UNSPEC_REJECT: return RPC_S_CALL_FAILED_DNE; + case NCA_S_BAD_ACTID: return RPC_S_CALL_FAILED_DNE; + case NCA_S_WHO_ARE_YOU_FAILED: return RPC_S_CALL_FAILED; + case NCA_S_MANAGER_NOT_ENTERED: return RPC_S_CALL_FAILED_DNE; + case NCA_S_FAULT_CANCEL: return RPC_S_CALL_CANCELLED; + case NCA_S_FAULT_ILL_INST: return RPC_S_ADDRESS_ERROR; + case NCA_S_FAULT_FP_ERROR: return RPC_S_FP_OVERFLOW; + case NCA_S_FAULT_INT_OVERFLOW: return RPC_S_ADDRESS_ERROR; + case NCA_S_FAULT_UNSPEC: return RPC_S_CALL_FAILED; + case NCA_S_FAULT_PIPE_EMPTY: return RPC_X_PIPE_EMPTY; + case NCA_S_FAULT_PIPE_CLOSED: return RPC_X_PIPE_CLOSED; + case NCA_S_FAULT_PIPE_ORDER: return RPC_X_WRONG_PIPE_ORDER; + case NCA_S_FAULT_PIPE_DISCIPLINE: return RPC_X_PIPE_DISCIPLINE_ERROR; + case NCA_S_FAULT_PIPE_COMM_ERROR: return RPC_S_COMM_FAILURE; + case NCA_S_FAULT_PIPE_MEMORY: return ERROR_OUTOFMEMORY; + case NCA_S_FAULT_CONTEXT_MISMATCH: return ERROR_INVALID_HANDLE; + case NCA_S_FAULT_REMOTE_NO_MEMORY: return ERROR_NOT_ENOUGH_SERVER_MEMORY; + default: return status; + } +} + +static RPC_STATUS RPCRT4_SecurePacket(RpcConnection *Connection, + enum secure_packet_direction dir, + RpcPktHdr *hdr, unsigned int hdr_size, + unsigned char *stub_data, unsigned int stub_data_size, + RpcAuthVerifier *auth_hdr, + unsigned char *auth_value, unsigned int auth_value_size) +{ + SecBufferDesc message; + SecBuffer buffers[4]; + SECURITY_STATUS sec_status; + + message.ulVersion = SECBUFFER_VERSION; + message.cBuffers = sizeof(buffers)/sizeof(buffers[0]); + message.pBuffers = buffers; + + buffers[0].cbBuffer = hdr_size; + buffers[0].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + buffers[0].pvBuffer = hdr; + buffers[1].cbBuffer = stub_data_size; + buffers[1].BufferType = SECBUFFER_DATA; + buffers[1].pvBuffer = stub_data; + buffers[2].cbBuffer = sizeof(*auth_hdr); + buffers[2].BufferType = SECBUFFER_DATA|SECBUFFER_READONLY_WITH_CHECKSUM; + buffers[2].pvBuffer = auth_hdr; + buffers[3].cbBuffer = auth_value_size; + buffers[3].BufferType = SECBUFFER_TOKEN; + buffers[3].pvBuffer = auth_value; + + if (dir == SECURE_PACKET_SEND) + { + if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr)) + { + sec_status = EncryptMessage(&Connection->ctx, 0, &message, 0 /* FIXME */); + if (sec_status != SEC_E_OK) + { + ERR("EncryptMessage failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE) + { + sec_status = MakeSignature(&Connection->ctx, 0, &message, 0 /* FIXME */); + if (sec_status != SEC_E_OK) + { + ERR("MakeSignature failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + } + else if (dir == SECURE_PACKET_RECEIVE) + { + if ((auth_hdr->auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(hdr)) + { + sec_status = DecryptMessage(&Connection->ctx, &message, 0 /* FIXME */, 0); + if (sec_status != SEC_E_OK) + { + ERR("EncryptMessage failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + else if (auth_hdr->auth_level != RPC_C_AUTHN_LEVEL_NONE) + { + sec_status = VerifySignature(&Connection->ctx, &message, 0 /* FIXME */, NULL); + if (sec_status != SEC_E_OK) + { + ERR("VerifySignature failed with 0x%08x\n", sec_status); + return RPC_S_SEC_PKG_ERROR; + } + } + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RPCRT4_SendAuth (internal) + * + * Transmit a packet with authorization data over connection in acceptable fragments. + */ +static RPC_STATUS RPCRT4_SendAuth(RpcConnection *Connection, RpcPktHdr *Header, + void *Buffer, unsigned int BufferLength, + void *Auth, unsigned int AuthLength) +{ + PUCHAR buffer_pos; + DWORD hdr_size; + LONG count; + unsigned char *pkt; + LONG alen; + RPC_STATUS status; + + buffer_pos = Buffer; + /* The packet building functions save the packet header size, so we can use it. */ + hdr_size = Header->common.frag_len; + if (AuthLength) + Header->common.auth_len = AuthLength; + else if (Connection->AuthInfo && packet_has_auth_verifier(Header)) + { + if ((Connection->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) && packet_has_body(Header)) + Header->common.auth_len = Connection->encryption_auth_len; + else + Header->common.auth_len = Connection->signature_auth_len; + } + else + Header->common.auth_len = 0; + Header->common.flags |= RPC_FLG_FIRST; + Header->common.flags &= ~RPC_FLG_LAST; + + alen = RPC_AUTH_VERIFIER_LEN(&Header->common); + + while (!(Header->common.flags & RPC_FLG_LAST)) { + unsigned char auth_pad_len = Header->common.auth_len ? ROUND_UP_AMOUNT(BufferLength, AUTH_ALIGNMENT) : 0; + unsigned int pkt_size = BufferLength + hdr_size + alen + auth_pad_len; + + /* decide if we need to split the packet into fragments */ + if (pkt_size <= Connection->MaxTransmissionSize) { + Header->common.flags |= RPC_FLG_LAST; + Header->common.frag_len = pkt_size; + } else { + auth_pad_len = 0; + /* make sure packet payload will be a multiple of 16 */ + Header->common.frag_len = + ((Connection->MaxTransmissionSize - hdr_size - alen) & ~(AUTH_ALIGNMENT-1)) + + hdr_size + alen; + } + + pkt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, Header->common.frag_len); + + memcpy(pkt, Header, hdr_size); + + /* fragment consisted of header only and is the last one */ + if (hdr_size == Header->common.frag_len) + goto write; + + memcpy(pkt + hdr_size, buffer_pos, Header->common.frag_len - hdr_size - auth_pad_len - alen); + + /* add the authorization info */ + if (Connection->AuthInfo && packet_has_auth_verifier(Header)) + { + RpcAuthVerifier *auth_hdr = (RpcAuthVerifier *)&pkt[Header->common.frag_len - alen]; + + auth_hdr->auth_type = Connection->AuthInfo->AuthnSvc; + auth_hdr->auth_level = Connection->AuthInfo->AuthnLevel; + auth_hdr->auth_pad_length = auth_pad_len; + auth_hdr->auth_reserved = 0; + /* a unique number... */ + auth_hdr->auth_context_id = (unsigned long)Connection; + + if (AuthLength) + memcpy(auth_hdr + 1, Auth, AuthLength); + else + { + status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_SEND, + (RpcPktHdr *)pkt, hdr_size, + pkt + hdr_size, Header->common.frag_len - hdr_size - alen, + auth_hdr, + (unsigned char *)(auth_hdr + 1), Header->common.auth_len); + if (status != RPC_S_OK) + { + HeapFree(GetProcessHeap(), 0, pkt); + return status; + } + } + } + +write: + count = rpcrt4_conn_write(Connection, pkt, Header->common.frag_len); + HeapFree(GetProcessHeap(), 0, pkt); + if (count<0) { + WARN("rpcrt4_conn_write failed (auth)\n"); + return RPC_S_PROTOCOL_ERROR; + } + + buffer_pos += Header->common.frag_len - hdr_size - alen - auth_pad_len; + BufferLength -= Header->common.frag_len - hdr_size - alen - auth_pad_len; + Header->common.flags &= ~RPC_FLG_FIRST; + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RPCRT4_ClientAuthorize (internal) + * + * Authorize a client connection. A NULL in param signifies a new connection. + */ +static RPC_STATUS RPCRT4_ClientAuthorize(RpcConnection *conn, SecBuffer *in, + SecBuffer *out) +{ + SECURITY_STATUS r; + SecBufferDesc out_desc; + SecBufferDesc inp_desc; + SecPkgContext_Sizes secctx_sizes; + BOOL continue_needed; + ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE | + ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE; + + if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_INTEGRITY) + context_req |= ISC_REQ_INTEGRITY; + else if (conn->AuthInfo->AuthnLevel == RPC_C_AUTHN_LEVEL_PKT_PRIVACY) + context_req |= ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY; + + out->BufferType = SECBUFFER_TOKEN; + out->cbBuffer = conn->AuthInfo->cbMaxToken; + out->pvBuffer = HeapAlloc(GetProcessHeap(), 0, out->cbBuffer); + if (!out->pvBuffer) return ERROR_OUTOFMEMORY; + + out_desc.ulVersion = 0; + out_desc.cBuffers = 1; + out_desc.pBuffers = out; + + inp_desc.cBuffers = 1; + inp_desc.pBuffers = in; + inp_desc.ulVersion = 0; + + r = InitializeSecurityContextA(&conn->AuthInfo->cred, in ? &conn->ctx : NULL, + NULL, context_req, 0, SECURITY_NETWORK_DREP, + in ? &inp_desc : NULL, 0, &conn->ctx, &out_desc, &conn->attr, + &conn->exp); + if (FAILED(r)) + { + WARN("InitializeSecurityContext failed with error 0x%08x\n", r); + goto failed; + } + + TRACE("r = 0x%08x, attr = 0x%08x\n", r, conn->attr); + continue_needed = ((r == SEC_I_CONTINUE_NEEDED) || + (r == SEC_I_COMPLETE_AND_CONTINUE)); + + if ((r == SEC_I_COMPLETE_NEEDED) || (r == SEC_I_COMPLETE_AND_CONTINUE)) + { + TRACE("complete needed\n"); + r = CompleteAuthToken(&conn->ctx, &out_desc); + if (FAILED(r)) + { + WARN("CompleteAuthToken failed with error 0x%08x\n", r); + goto failed; + } + } + + TRACE("cbBuffer = %ld\n", out->cbBuffer); + + if (!continue_needed) + { + r = QueryContextAttributesA(&conn->ctx, SECPKG_ATTR_SIZES, &secctx_sizes); + if (FAILED(r)) + { + WARN("QueryContextAttributes failed with error 0x%08x\n", r); + goto failed; + } + conn->signature_auth_len = secctx_sizes.cbMaxSignature; + conn->encryption_auth_len = secctx_sizes.cbSecurityTrailer; + } + + return RPC_S_OK; + +failed: + HeapFree(GetProcessHeap(), 0, out->pvBuffer); + out->pvBuffer = NULL; + return ERROR_ACCESS_DENIED; /* FIXME: is this correct? */ +} + +/*********************************************************************** + * RPCRT4_AuthorizeBinding (internal) + */ +static RPC_STATUS RPCRT_AuthorizeConnection(RpcConnection* conn, + BYTE *challenge, ULONG count) +{ + SecBuffer inp, out; + RpcPktHdr *resp_hdr; + RPC_STATUS status; + + TRACE("challenge %s, %d bytes\n", challenge, count); + + inp.BufferType = SECBUFFER_TOKEN; + inp.pvBuffer = challenge; + inp.cbBuffer = count; + + status = RPCRT4_ClientAuthorize(conn, &inp, &out); + if (status) return status; + + resp_hdr = RPCRT4_BuildAuthHeader(NDR_LOCAL_DATA_REPRESENTATION); + if (!resp_hdr) + return E_OUTOFMEMORY; + + status = RPCRT4_SendAuth(conn, resp_hdr, NULL, 0, out.pvBuffer, out.cbBuffer); + + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + RPCRT4_FreeHeader(resp_hdr); + + return status; +} + +/*********************************************************************** + * RPCRT4_Send (internal) + * + * Transmit a packet over connection in acceptable fragments. + */ +RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, + void *Buffer, unsigned int BufferLength) +{ + RPC_STATUS r; + SecBuffer out; + + if (!Connection->AuthInfo || SecIsValidHandle(&Connection->ctx)) + { + return RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, NULL, 0); + } + + /* tack on a negotiate packet */ + RPCRT4_ClientAuthorize(Connection, NULL, &out); + r = RPCRT4_SendAuth(Connection, Header, Buffer, BufferLength, out.pvBuffer, out.cbBuffer); + HeapFree(GetProcessHeap(), 0, out.pvBuffer); + + return r; +} + +/*********************************************************************** + * RPCRT4_Receive (internal) + * + * Receive a packet from connection and merge the fragments. + */ +RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, + PRPC_MESSAGE pMsg) +{ + RPC_STATUS status; + DWORD hdr_length; + LONG dwRead; + unsigned short first_flag; + unsigned long data_length; + unsigned long buffer_length; + unsigned long auth_length; + unsigned char *auth_data = NULL; + RpcPktCommonHdr common_hdr; + + *Header = NULL; + + TRACE("(%p, %p, %p)\n", Connection, Header, pMsg); + + /* read packet common header */ + dwRead = rpcrt4_conn_read(Connection, &common_hdr, sizeof(common_hdr)); + if (dwRead != sizeof(common_hdr)) { + WARN("Short read of header, %d bytes\n", dwRead); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* verify if the header really makes sense */ + if (common_hdr.rpc_ver != RPC_VER_MAJOR || + common_hdr.rpc_ver_minor != RPC_VER_MINOR) { + WARN("unhandled packet version\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + hdr_length = RPCRT4_GetHeaderSize((RpcPktHdr*)&common_hdr); + if (hdr_length == 0) { + WARN("header length == 0\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + *Header = HeapAlloc(GetProcessHeap(), 0, hdr_length); + memcpy(*Header, &common_hdr, sizeof(common_hdr)); + + /* read the rest of packet header */ + dwRead = rpcrt4_conn_read(Connection, &(*Header)->common + 1, hdr_length - sizeof(common_hdr)); + if (dwRead != hdr_length - sizeof(common_hdr)) { + WARN("bad header length, %d bytes, hdr_length %d\n", dwRead, hdr_length); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* read packet body */ + switch (common_hdr.ptype) { + case PKT_RESPONSE: + pMsg->BufferLength = (*Header)->response.alloc_hint; + break; + case PKT_REQUEST: + pMsg->BufferLength = (*Header)->request.alloc_hint; + break; + default: + pMsg->BufferLength = common_hdr.frag_len - hdr_length - RPC_AUTH_VERIFIER_LEN(&common_hdr); + } + + TRACE("buffer length = %u\n", pMsg->BufferLength); + + status = I_RpcGetBuffer(pMsg); + if (status != RPC_S_OK) goto fail; + + first_flag = RPC_FLG_FIRST; + auth_length = common_hdr.auth_len; + if (auth_length) { + auth_data = HeapAlloc(GetProcessHeap(), 0, RPC_AUTH_VERIFIER_LEN(&common_hdr)); + if (!auth_data) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + } + buffer_length = 0; + while (TRUE) + { + unsigned int header_auth_len = RPC_AUTH_VERIFIER_LEN(&(*Header)->common); + + /* verify header fields */ + + if (((*Header)->common.frag_len < hdr_length) || + ((*Header)->common.frag_len - hdr_length < header_auth_len)) { + WARN("frag_len %d too small for hdr_length %d and auth_len %d\n", + (*Header)->common.frag_len, hdr_length, header_auth_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if ((*Header)->common.auth_len != auth_length) { + WARN("auth_len header field changed from %ld to %d\n", + auth_length, (*Header)->common.auth_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if (((*Header)->common.flags & RPC_FLG_FIRST) != first_flag) { + TRACE("invalid packet flags\n"); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + data_length = (*Header)->common.frag_len - hdr_length - header_auth_len; + if (data_length + buffer_length > pMsg->BufferLength) { + TRACE("allocation hint exceeded, new buffer length = %ld\n", + data_length + buffer_length); + pMsg->BufferLength = data_length + buffer_length; + status = I_RpcReAllocateBuffer(pMsg); + if (status != RPC_S_OK) goto fail; + } + + if (data_length == 0) dwRead = 0; else + dwRead = rpcrt4_conn_read(Connection, + (unsigned char *)pMsg->Buffer + buffer_length, data_length); + if (dwRead != data_length) { + WARN("bad data length, %d/%ld\n", dwRead, data_length); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + if (header_auth_len) { + if (header_auth_len < sizeof(RpcAuthVerifier)) { + WARN("bad auth verifier length %d\n", header_auth_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* FIXME: we should accumulate authentication data for the bind, + * bind_ack, alter_context and alter_context_response if necessary. + * however, the details of how this is done is very sketchy in the + * DCE/RPC spec. for all other packet types that have authentication + * verifier data then it is just duplicated in all the fragments */ + dwRead = rpcrt4_conn_read(Connection, auth_data, header_auth_len); + if (dwRead != header_auth_len) { + WARN("bad authentication data length, %d/%d\n", dwRead, + header_auth_len); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* these packets are handled specially, not by the generic SecurePacket + * function */ + if ((common_hdr.ptype != PKT_BIND) && + (common_hdr.ptype != PKT_BIND_ACK) && + (common_hdr.ptype != PKT_AUTH3)) + status = RPCRT4_SecurePacket(Connection, SECURE_PACKET_RECEIVE, + *Header, hdr_length, + (unsigned char *)pMsg->Buffer + buffer_length, data_length, + (RpcAuthVerifier *)auth_data, + (unsigned char *)auth_data + sizeof(RpcAuthVerifier), + header_auth_len - sizeof(RpcAuthVerifier)); + } + + buffer_length += data_length; + if (!((*Header)->common.flags & RPC_FLG_LAST)) { + TRACE("next header\n"); + + /* read the header of next packet */ + dwRead = rpcrt4_conn_read(Connection, *Header, hdr_length); + if (dwRead != hdr_length) { + WARN("invalid packet header size (%d)\n", dwRead); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + first_flag = 0; + } else { + break; + } + } + pMsg->BufferLength = buffer_length; + + /* respond to authorization request */ + if (common_hdr.ptype == PKT_BIND_ACK && auth_length > sizeof(RpcAuthVerifier)) + { + status = RPCRT_AuthorizeConnection(Connection, + auth_data + sizeof(RpcAuthVerifier), + auth_length); + if (status) + goto fail; + } + + /* success */ + status = RPC_S_OK; + +fail: + if (status != RPC_S_OK) { + RPCRT4_FreeHeader(*Header); + *Header = NULL; + } + HeapFree(GetProcessHeap(), 0, auth_data); + return status; +} + +/*********************************************************************** + * I_RpcGetBuffer [RPCRT4.@] + * + * Allocates a buffer for use by I_RpcSend or I_RpcSendReceive and binds to the + * server interface. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * Success: RPC_S_OK. + * Failure: RPC_S_INVALID_BINDING if pMsg->Handle is invalid. + * RPC_S_SERVER_UNAVAILABLE if unable to connect to server. + * ERROR_OUTOFMEMORY if buffer allocation failed. + * + * NOTES + * The pMsg->BufferLength field determines the size of the buffer to allocate, + * in bytes. + * + * Use I_RpcFreeBuffer() to unbind from the server and free the message buffer. + * + * SEE ALSO + * I_RpcFreeBuffer(), I_RpcSend(), I_RpcReceive(), I_RpcSendReceive(). + */ +RPC_STATUS WINAPI I_RpcGetBuffer(PRPC_MESSAGE pMsg) +{ + TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); + /* FIXME: pfnAllocate? */ + pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->BufferLength); + + TRACE("Buffer=%p\n", pMsg->Buffer); + /* FIXME: which errors to return? */ + return pMsg->Buffer ? S_OK : E_OUTOFMEMORY; +} + +/*********************************************************************** + * I_RpcReAllocateBuffer (internal) + */ +static RPC_STATUS I_RpcReAllocateBuffer(PRPC_MESSAGE pMsg) +{ + TRACE("(%p): BufferLength=%d\n", pMsg, pMsg->BufferLength); + pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->BufferLength); + + TRACE("Buffer=%p\n", pMsg->Buffer); + return pMsg->Buffer ? RPC_S_OK : RPC_S_OUT_OF_RESOURCES; +} + +/*********************************************************************** + * I_RpcFreeBuffer [RPCRT4.@] + * + * Frees a buffer allocated by I_RpcGetBuffer or I_RpcReceive and unbinds from + * the server interface. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * RPC_S_OK. + * + * SEE ALSO + * I_RpcGetBuffer(), I_RpcReceive(). + */ +RPC_STATUS WINAPI I_RpcFreeBuffer(PRPC_MESSAGE pMsg) +{ + TRACE("(%p) Buffer=%p\n", pMsg, pMsg->Buffer); + /* FIXME: pfnFree? */ + HeapFree(GetProcessHeap(), 0, pMsg->Buffer); + pMsg->Buffer = NULL; + return S_OK; +} + +/*********************************************************************** + * I_RpcSend [RPCRT4.@] + * + * Sends a message to the server. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * Unknown. + * + * NOTES + * The buffer must have been allocated with I_RpcGetBuffer(). + * + * SEE ALSO + * I_RpcGetBuffer(), I_RpcReceive(), I_RpcSendReceive(). + */ +RPC_STATUS WINAPI I_RpcSend(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcConnection* conn; + RPC_CLIENT_INTERFACE* cif = NULL; + RPC_STATUS status; + RpcPktHdr *hdr; + + TRACE("(%p)\n", pMsg); + if (!bind || bind->server) return RPC_S_INVALID_BINDING; + + cif = pMsg->RpcInterfaceInformation; + if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + + if (!bind->Endpoint || !bind->Endpoint[0]) + { + TRACE("automatically resolving partially bound binding\n"); + status = RpcEpResolveBinding(bind, cif); + if (status != RPC_S_OK) return status; + } + + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, + &cif->InterfaceId); + if (status != RPC_S_OK) return status; + + hdr = RPCRT4_BuildRequestHeader(pMsg->DataRepresentation, + pMsg->BufferLength, pMsg->ProcNum, + &bind->ObjectUuid); + if (!hdr) + { + RPCRT4_CloseBinding(bind, conn); + return ERROR_OUTOFMEMORY; + } + hdr->common.call_id = conn->NextCallId++; + + status = RPCRT4_Send(conn, hdr, pMsg->Buffer, pMsg->BufferLength); + + RPCRT4_FreeHeader(hdr); + + /* save the connection, so the response can be read from it */ + pMsg->ReservedForRuntime = conn; + return status; +} + +/* is this status something that the server can't recover from? */ +static inline BOOL is_hard_error(RPC_STATUS status) +{ + switch (status) + { + case 0: /* user-defined fault */ + case ERROR_ACCESS_DENIED: + case ERROR_INVALID_PARAMETER: + case RPC_S_PROTOCOL_ERROR: + case RPC_S_CALL_FAILED: + case RPC_S_CALL_FAILED_DNE: + return TRUE; + default: + return FALSE; + } +} + +/*********************************************************************** + * I_RpcReceive [RPCRT4.@] + */ +RPC_STATUS WINAPI I_RpcReceive(PRPC_MESSAGE pMsg) +{ + RpcBinding* bind = (RpcBinding*)pMsg->Handle; + RpcConnection* conn; + RPC_CLIENT_INTERFACE* cif = NULL; + RPC_SERVER_INTERFACE* sif = NULL; + RPC_STATUS status; + RpcPktHdr *hdr = NULL; + + TRACE("(%p)\n", pMsg); + if (!bind) return RPC_S_INVALID_BINDING; + + if (pMsg->ReservedForRuntime) { + conn = pMsg->ReservedForRuntime; + pMsg->ReservedForRuntime = NULL; + } else { + if (bind->server) { + sif = pMsg->RpcInterfaceInformation; + if (!sif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + status = RPCRT4_OpenBinding(bind, &conn, &sif->TransferSyntax, + &sif->InterfaceId); + } else { + cif = pMsg->RpcInterfaceInformation; + if (!cif) return RPC_S_INTERFACE_NOT_FOUND; /* ? */ + + if (!bind->Endpoint || !bind->Endpoint[0]) + { + TRACE("automatically resolving partially bound binding\n"); + status = RpcEpResolveBinding(bind, cif); + if (status != RPC_S_OK) return status; + } + + status = RPCRT4_OpenBinding(bind, &conn, &cif->TransferSyntax, + &cif->InterfaceId); + } + if (status != RPC_S_OK) return status; + } + + status = RPCRT4_Receive(conn, &hdr, pMsg); + if (status != RPC_S_OK) { + WARN("receive failed with error %lx\n", status); + goto fail; + } + + switch (hdr->common.ptype) { + case PKT_RESPONSE: + if (bind->server) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + break; + case PKT_REQUEST: + if (!bind->server) { + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + break; + case PKT_FAULT: + ERR ("we got fault packet with status 0x%lx\n", hdr->fault.status); + status = NCA2RPC_STATUS(hdr->fault.status); + if (is_hard_error(status)) + goto fail; + break; + default: + WARN("bad packet type %d\n", hdr->common.ptype); + status = RPC_S_PROTOCOL_ERROR; + goto fail; + } + + /* success */ + RPCRT4_CloseBinding(bind, conn); + RPCRT4_FreeHeader(hdr); + return status; + +fail: + RPCRT4_FreeHeader(hdr); + RPCRT4_DestroyConnection(conn); + return status; +} + +/*********************************************************************** + * I_RpcSendReceive [RPCRT4.@] + * + * Sends a message to the server and receives the response. + * + * PARAMS + * pMsg [I/O] RPC message information. + * + * RETURNS + * Success: RPC_S_OK. + * Failure: Any error code. + * + * NOTES + * The buffer must have been allocated with I_RpcGetBuffer(). + * + * SEE ALSO + * I_RpcGetBuffer(), I_RpcSend(), I_RpcReceive(). + */ +RPC_STATUS WINAPI I_RpcSendReceive(PRPC_MESSAGE pMsg) +{ + RPC_STATUS status; + RPC_MESSAGE original_message; + + TRACE("(%p)\n", pMsg); + + original_message = *pMsg; + status = I_RpcSend(pMsg); + if (status == RPC_S_OK) + status = I_RpcReceive(pMsg); + /* free the buffer replaced by a new buffer in I_RpcReceive */ + if (status == RPC_S_OK) + I_RpcFreeBuffer(&original_message); + return status; +} diff --git a/reactos/dll/win32/rpcrt4_new/rpc_message.h b/reactos/dll/win32/rpcrt4_new/rpc_message.h new file mode 100644 index 00000000000..8815d8d2dec --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_message.h @@ -0,0 +1,40 @@ +/* + * RPC message API + * + * Copyright 2004 Filip Navara + * + * 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 + */ + +#ifndef __WINE_RPC_MESSAGE_H +#define __WINE_RPC_MESSAGE_H + +#include "wine/rpcss_shared.h" +#include "rpc_defs.h" + +typedef unsigned int NCA_STATUS; + +RpcPktHdr *RPCRT4_BuildFaultHeader(unsigned long DataRepresentation, RPC_STATUS Status); +RpcPktHdr *RPCRT4_BuildResponseHeader(unsigned long DataRepresentation, unsigned long BufferLength); +RpcPktHdr *RPCRT4_BuildBindHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, unsigned long AssocGroupId, const RPC_SYNTAX_IDENTIFIER *AbstractId, const RPC_SYNTAX_IDENTIFIER *TransferId); +RpcPktHdr *RPCRT4_BuildBindNackHeader(unsigned long DataRepresentation, unsigned char RpcVersion, unsigned char RpcVersionMinor); +RpcPktHdr *RPCRT4_BuildBindAckHeader(unsigned long DataRepresentation, unsigned short MaxTransmissionSize, unsigned short MaxReceiveSize, LPCSTR ServerAddress, unsigned long Result, unsigned long Reason, const RPC_SYNTAX_IDENTIFIER *TransferId); +VOID RPCRT4_FreeHeader(RpcPktHdr *Header); +RPC_STATUS RPCRT4_Send(RpcConnection *Connection, RpcPktHdr *Header, void *Buffer, unsigned int BufferLength); +RPC_STATUS RPCRT4_Receive(RpcConnection *Connection, RpcPktHdr **Header, PRPC_MESSAGE pMsg); +NCA_STATUS RPC2NCA_STATUS(RPC_STATUS status); +RPC_STATUS NCA2RPC_STATUS(NCA_STATUS status); + +#endif diff --git a/reactos/dll/win32/rpcrt4_new/rpc_misc.h b/reactos/dll/win32/rpcrt4_new/rpc_misc.h new file mode 100644 index 00000000000..0cb41c1b7be --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_misc.h @@ -0,0 +1,28 @@ +/* + * RPC definitions + * + * Copyright 2003 Ove Kåven, TransGaming Technologies + * + * 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 + * + */ + +#ifndef __WINE_RPC_MISC_H +#define __WINE_RPC_MISC_H + +/* flags for RPC_MESSAGE.RpcFlags */ +#define WINE_RPCFLAG_EXCEPTION 0x0001 + +#endif /* __WINE_RPC_MISC_H */ diff --git a/reactos/dll/win32/rpcrt4_new/rpc_server.c b/reactos/dll/win32/rpcrt4_new/rpc_server.c new file mode 100644 index 00000000000..328c0d0fc96 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_server.c @@ -0,0 +1,1116 @@ +/* + * RPC server API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2004 Filip Navara + * + * 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 + * + * TODO: + * - a whole lot + */ + +#include "config.h" +#include "wine/port.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winerror.h" + +#include "rpc.h" +#include "rpcndr.h" +#include "excpt.h" + +#include "wine/debug.h" +#include "wine/exception.h" + +#include "rpc_server.h" +#include "rpc_message.h" +#include "rpc_defs.h" +#include "ncastatus.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +typedef struct _RpcPacket +{ + struct _RpcConnection* conn; + RpcPktHdr* hdr; + RPC_MESSAGE* msg; +} RpcPacket; + +typedef struct _RpcObjTypeMap +{ + /* FIXME: a hash table would be better. */ + struct _RpcObjTypeMap *next; + UUID Object; + UUID Type; +} RpcObjTypeMap; + +static RpcObjTypeMap *RpcObjTypeMaps; + +/* list of type RpcServerProtseq */ +static struct list protseqs = LIST_INIT(protseqs); +static struct list server_interfaces = LIST_INIT(server_interfaces); + +static CRITICAL_SECTION server_cs; +static CRITICAL_SECTION_DEBUG server_cs_debug = +{ + 0, 0, &server_cs, + { &server_cs_debug.ProcessLocksList, &server_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": server_cs") } +}; +static CRITICAL_SECTION server_cs = { &server_cs_debug, -1, 0, 0, 0, 0 }; + +static CRITICAL_SECTION listen_cs; +static CRITICAL_SECTION_DEBUG listen_cs_debug = +{ + 0, 0, &listen_cs, + { &listen_cs_debug.ProcessLocksList, &listen_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": listen_cs") } +}; +static CRITICAL_SECTION listen_cs = { &listen_cs_debug, -1, 0, 0, 0, 0 }; + +/* whether the server is currently listening */ +static BOOL std_listen; +/* number of manual listeners (calls to RpcServerListen) */ +static LONG manual_listen_count; +/* total listeners including auto listeners */ +static LONG listen_count; + +static UUID uuid_nil; + +static inline RpcObjTypeMap *LookupObjTypeMap(UUID *ObjUuid) +{ + RpcObjTypeMap *rslt = RpcObjTypeMaps; + RPC_STATUS dummy; + + while (rslt) { + if (! UuidCompare(ObjUuid, &rslt->Object, &dummy)) break; + rslt = rslt->next; + } + + return rslt; +} + +static inline UUID *LookupObjType(UUID *ObjUuid) +{ + RpcObjTypeMap *map = LookupObjTypeMap(ObjUuid); + if (map) + return &map->Type; + else + return &uuid_nil; +} + +static RpcServerInterface* RPCRT4_find_interface(UUID* object, + RPC_SYNTAX_IDENTIFIER* if_id, + BOOL check_object) +{ + UUID* MgrType = NULL; + RpcServerInterface* cif; + RPC_STATUS status; + + if (check_object) + MgrType = LookupObjType(object); + EnterCriticalSection(&server_cs); + LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) { + if (!memcmp(if_id, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER)) && + (check_object == FALSE || UuidEqual(MgrType, &cif->MgrTypeUuid, &status)) && + std_listen) { + InterlockedIncrement(&cif->CurrentCalls); + break; + } + } + LeaveCriticalSection(&server_cs); + if (&cif->entry == &server_interfaces) cif = NULL; + TRACE("returning %p for %s\n", cif, debugstr_guid(object)); + return cif; +} + +static void RPCRT4_release_server_interface(RpcServerInterface *sif) +{ + if (!InterlockedDecrement(&sif->CurrentCalls) && + sif->CallsCompletedEvent) { + /* sif must have been removed from server_interfaces before + * CallsCompletedEvent is set */ + SetEvent(sif->CallsCompletedEvent); + HeapFree(GetProcessHeap(), 0, sif); + } +} + +static WINE_EXCEPTION_FILTER(rpc_filter) +{ + WARN("exception caught with code 0x%08x = %d\n", GetExceptionCode(), GetExceptionCode()); + TRACE("returning failure packet\n"); + /* catch every exception */ + return EXCEPTION_EXECUTE_HANDLER; +} + +static void RPCRT4_process_packet(RpcConnection* conn, RpcPktHdr* hdr, RPC_MESSAGE* msg) +{ + RpcServerInterface* sif; + RPC_DISPATCH_FUNCTION func; + UUID *object_uuid; + RpcPktHdr *response; + void *buf = msg->Buffer; + RPC_STATUS status; + BOOL exception; + + switch (hdr->common.ptype) { + case PKT_BIND: + TRACE("got bind packet\n"); + + /* FIXME: do more checks! */ + if (hdr->bind.max_tsize < RPC_MIN_PACKET_SIZE || + !UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { + TRACE("packet size less than min size, or active interface syntax guid non-null\n"); + sif = NULL; + } else { + sif = RPCRT4_find_interface(NULL, &hdr->bind.abstract, FALSE); + } + if (sif == NULL) { + TRACE("rejecting bind request on connection %p\n", conn); + /* Report failure to client. */ + response = RPCRT4_BuildBindNackHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_VER_MAJOR, RPC_VER_MINOR); + } else { + TRACE("accepting bind request on connection %p for %s\n", conn, + debugstr_guid(&hdr->bind.abstract.SyntaxGUID)); + + /* accept. */ + response = RPCRT4_BuildBindAckHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, + RPC_MAX_PACKET_SIZE, + conn->Endpoint, + RESULT_ACCEPT, NO_REASON, + &sif->If->TransferSyntax); + + /* save the interface for later use */ + conn->ActiveInterface = hdr->bind.abstract; + conn->MaxTransmissionSize = hdr->bind.max_tsize; + + RPCRT4_release_server_interface(sif); + } + + status = RPCRT4_Send(conn, response, NULL, 0); + RPCRT4_FreeHeader(response); + if (status != RPC_S_OK) + goto fail; + + break; + + case PKT_REQUEST: + TRACE("got request packet\n"); + + /* fail if the connection isn't bound with an interface */ + if (UuidIsNil(&conn->ActiveInterface.SyntaxGUID, &status)) { + /* FIXME: should send BindNack instead */ + response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, + status); + + RPCRT4_Send(conn, response, NULL, 0); + RPCRT4_FreeHeader(response); + break; + } + + if (hdr->common.flags & RPC_FLG_OBJECT_UUID) { + object_uuid = (UUID*)(&hdr->request + 1); + } else { + object_uuid = NULL; + } + + sif = RPCRT4_find_interface(object_uuid, &conn->ActiveInterface, TRUE); + if (!sif) { + WARN("interface %s no longer registered, returning fault packet\n", debugstr_guid(&conn->ActiveInterface.SyntaxGUID)); + response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, + NCA_S_UNK_IF); + + RPCRT4_Send(conn, response, NULL, 0); + RPCRT4_FreeHeader(response); + break; + } + msg->RpcInterfaceInformation = sif->If; + /* copy the endpoint vector from sif to msg so that midl-generated code will use it */ + msg->ManagerEpv = sif->MgrEpv; + if (object_uuid != NULL) { + RPCRT4_SetBindingObject(msg->Handle, object_uuid); + } + + /* find dispatch function */ + msg->ProcNum = hdr->request.opnum; + if (sif->Flags & RPC_IF_OLE) { + /* native ole32 always gives us a dispatch table with a single entry + * (I assume that's a wrapper for IRpcStubBuffer::Invoke) */ + func = *sif->If->DispatchTable->DispatchTable; + } else { + if (msg->ProcNum >= sif->If->DispatchTable->DispatchTableCount) { + WARN("invalid procnum (%d/%d)\n", msg->ProcNum, sif->If->DispatchTable->DispatchTableCount); + response = RPCRT4_BuildFaultHeader(NDR_LOCAL_DATA_REPRESENTATION, + NCA_S_OP_RNG_ERROR); + + RPCRT4_Send(conn, response, NULL, 0); + RPCRT4_FreeHeader(response); + } + func = sif->If->DispatchTable->DispatchTable[msg->ProcNum]; + } + + /* put in the drep. FIXME: is this more universally applicable? + perhaps we should move this outward... */ + msg->DataRepresentation = + MAKELONG( MAKEWORD(hdr->common.drep[0], hdr->common.drep[1]), + MAKEWORD(hdr->common.drep[2], hdr->common.drep[3])); + + exception = FALSE; + + /* dispatch */ + __TRY { + if (func) func(msg); + } __EXCEPT(rpc_filter) { + exception = TRUE; + if (GetExceptionCode() == STATUS_ACCESS_VIOLATION) + status = ERROR_NOACCESS; + else + status = GetExceptionCode(); + response = RPCRT4_BuildFaultHeader(msg->DataRepresentation, + RPC2NCA_STATUS(status)); + } __ENDTRY + + if (!exception) + response = RPCRT4_BuildResponseHeader(msg->DataRepresentation, + msg->BufferLength); + + /* send response packet */ + if (response) { + status = RPCRT4_Send(conn, response, exception ? NULL : msg->Buffer, + exception ? 0 : msg->BufferLength); + RPCRT4_FreeHeader(response); + } else + ERR("out of memory\n"); + + msg->RpcInterfaceInformation = NULL; + RPCRT4_release_server_interface(sif); + + break; + + default: + FIXME("unhandled packet type %u\n", hdr->common.ptype); + break; + } + +fail: + /* clean up */ + if (msg->Buffer == buf) msg->Buffer = NULL; + TRACE("freeing Buffer=%p\n", buf); + HeapFree(GetProcessHeap(), 0, buf); + RPCRT4_DestroyBinding(msg->Handle); + msg->Handle = 0; + I_RpcFreeBuffer(msg); + msg->Buffer = NULL; + RPCRT4_FreeHeader(hdr); + HeapFree(GetProcessHeap(), 0, msg); +} + +static DWORD CALLBACK RPCRT4_worker_thread(LPVOID the_arg) +{ + RpcPacket *pkt = the_arg; + RPCRT4_process_packet(pkt->conn, pkt->hdr, pkt->msg); + HeapFree(GetProcessHeap(), 0, pkt); + return 0; +} + +static DWORD CALLBACK RPCRT4_io_thread(LPVOID the_arg) +{ + RpcConnection* conn = (RpcConnection*)the_arg; + RpcPktHdr *hdr; + RpcBinding *pbind; + RPC_MESSAGE *msg; + RPC_STATUS status; + RpcPacket *packet; + + TRACE("(%p)\n", conn); + + for (;;) { + msg = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_MESSAGE)); + + /* create temporary binding for dispatch, it will be freed in + * RPCRT4_process_packet */ + RPCRT4_MakeBinding(&pbind, conn); + msg->Handle = (RPC_BINDING_HANDLE)pbind; + + status = RPCRT4_Receive(conn, &hdr, msg); + if (status != RPC_S_OK) { + WARN("receive failed with error %lx\n", status); + HeapFree(GetProcessHeap(), 0, msg); + break; + } + +#if 0 + RPCRT4_process_packet(conn, hdr, msg); +#else + packet = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcPacket)); + packet->conn = conn; + packet->hdr = hdr; + packet->msg = msg; + QueueUserWorkItem(RPCRT4_worker_thread, packet, WT_EXECUTELONGFUNCTION); +#endif + msg = NULL; + } + RPCRT4_DestroyConnection(conn); + return 0; +} + +void RPCRT4_new_client(RpcConnection* conn) +{ + HANDLE thread = CreateThread(NULL, 0, RPCRT4_io_thread, conn, 0, NULL); + if (!thread) { + DWORD err = GetLastError(); + ERR("failed to create thread, error=%08x\n", err); + RPCRT4_DestroyConnection(conn); + } + /* we could set conn->thread, but then we'd have to make the io_thread wait + * for that, otherwise the thread might finish, destroy the connection, and + * free the memory we'd write to before we did, causing crashes and stuff - + * so let's implement that later, when we really need conn->thread */ + + CloseHandle( thread ); +} + +static DWORD CALLBACK RPCRT4_server_thread(LPVOID the_arg) +{ + int res; + unsigned int count; + void *objs = NULL; + RpcServerProtseq* cps = the_arg; + RpcConnection* conn; + BOOL set_ready_event = FALSE; + + TRACE("(the_arg == ^%p)\n", the_arg); + + for (;;) { + objs = cps->ops->get_wait_array(cps, objs, &count); + + if (set_ready_event) + { + /* signal to function that changed state that we are now sync'ed */ + SetEvent(cps->server_ready_event); + set_ready_event = FALSE; + } + + /* start waiting */ + res = cps->ops->wait_for_new_connection(cps, count, objs); + if (res == -1) + break; + else if (res == 0) + { + if (!std_listen) + { + SetEvent(cps->server_ready_event); + break; + } + set_ready_event = TRUE; + } + } + cps->ops->free_wait_array(cps, objs); + EnterCriticalSection(&cps->cs); + /* close connections */ + conn = cps->conn; + while (conn) { + RPCRT4_CloseConnection(conn); + conn = conn->Next; + } + LeaveCriticalSection(&cps->cs); + return 0; +} + +/* tells the server thread that the state has changed and waits for it to + * make the changes */ +static void RPCRT4_sync_with_server_thread(RpcServerProtseq *ps) +{ + /* make sure we are the only thread sync'ing the server state, otherwise + * there is a race with the server thread setting an older state and setting + * the server_ready_event when the new state hasn't yet been applied */ + WaitForSingleObject(ps->mgr_mutex, INFINITE); + + ps->ops->signal_state_changed(ps); + + /* wait for server thread to make the requested changes before returning */ + WaitForSingleObject(ps->server_ready_event, INFINITE); + + ReleaseMutex(ps->mgr_mutex); +} + +static RPC_STATUS RPCRT4_start_listen_protseq(RpcServerProtseq *ps, BOOL auto_listen) +{ + RPC_STATUS status = RPC_S_OK; + HANDLE server_thread; + + EnterCriticalSection(&listen_cs); + if (ps->is_listening) goto done; + + if (!ps->mgr_mutex) ps->mgr_mutex = CreateMutexW(NULL, FALSE, NULL); + if (!ps->server_ready_event) ps->server_ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + server_thread = CreateThread(NULL, 0, RPCRT4_server_thread, ps, 0, NULL); + if (!server_thread) + { + status = RPC_S_OUT_OF_RESOURCES; + goto done; + } + ps->is_listening = TRUE; + CloseHandle(server_thread); + +done: + LeaveCriticalSection(&listen_cs); + return status; +} + +static RPC_STATUS RPCRT4_start_listen(BOOL auto_listen) +{ + RPC_STATUS status = RPC_S_ALREADY_LISTENING; + RpcServerProtseq *cps; + + TRACE("\n"); + + EnterCriticalSection(&listen_cs); + if (auto_listen || (manual_listen_count++ == 0)) + { + status = RPC_S_OK; + if (++listen_count == 1) + std_listen = TRUE; + } + LeaveCriticalSection(&listen_cs); + + if (std_listen) + { + EnterCriticalSection(&server_cs); + LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry) + { + status = RPCRT4_start_listen_protseq(cps, TRUE); + if (status != RPC_S_OK) + break; + + /* make sure server is actually listening on the interface before + * returning */ + RPCRT4_sync_with_server_thread(cps); + } + LeaveCriticalSection(&server_cs); + } + + return status; +} + +static void RPCRT4_stop_listen(BOOL auto_listen) +{ + EnterCriticalSection(&listen_cs); + if (auto_listen || (--manual_listen_count == 0)) + { + if (listen_count != 0 && --listen_count == 0) { + RpcServerProtseq *cps; + + std_listen = FALSE; + LeaveCriticalSection(&listen_cs); + + LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry) + RPCRT4_sync_with_server_thread(cps); + + return; + } + assert(listen_count >= 0); + } + LeaveCriticalSection(&listen_cs); +} + +static RPC_STATUS RPCRT4_use_protseq(RpcServerProtseq* ps, LPSTR endpoint) +{ + RPC_STATUS status; + + status = ps->ops->open_endpoint(ps, endpoint); + if (status != RPC_S_OK) + return status; + + if (std_listen) + { + status = RPCRT4_start_listen_protseq(ps, FALSE); + if (status == RPC_S_OK) + RPCRT4_sync_with_server_thread(ps); + } + + return status; +} + +/*********************************************************************** + * RpcServerInqBindings (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerInqBindings( RPC_BINDING_VECTOR** BindingVector ) +{ + RPC_STATUS status; + DWORD count; + RpcServerProtseq* ps; + RpcConnection* conn; + + if (BindingVector) + TRACE("(*BindingVector == ^%p)\n", *BindingVector); + else + ERR("(BindingVector == NULL!!?)\n"); + + EnterCriticalSection(&server_cs); + /* count connections */ + count = 0; + LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) { + EnterCriticalSection(&ps->cs); + conn = ps->conn; + while (conn) { + count++; + conn = conn->Next; + } + LeaveCriticalSection(&ps->cs); + } + if (count) { + /* export bindings */ + *BindingVector = HeapAlloc(GetProcessHeap(), 0, + sizeof(RPC_BINDING_VECTOR) + + sizeof(RPC_BINDING_HANDLE)*(count-1)); + (*BindingVector)->Count = count; + count = 0; + LIST_FOR_EACH_ENTRY(ps, &protseqs, RpcServerProtseq, entry) { + EnterCriticalSection(&ps->cs); + conn = ps->conn; + while (conn) { + RPCRT4_MakeBinding((RpcBinding**)&(*BindingVector)->BindingH[count], + conn); + count++; + conn = conn->Next; + } + LeaveCriticalSection(&ps->cs); + } + status = RPC_S_OK; + } else { + *BindingVector = NULL; + status = RPC_S_NO_BINDINGS; + } + LeaveCriticalSection(&server_cs); + return status; +} + +/*********************************************************************** + * RpcServerUseProtseqEpA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor ) +{ + RPC_POLICY policy; + + TRACE( "(%s,%u,%s,%p)\n", Protseq, MaxCalls, Endpoint, SecurityDescriptor ); + + /* This should provide the default behaviour */ + policy.Length = sizeof( policy ); + policy.EndpointFlags = 0; + policy.NICFlags = 0; + + return RpcServerUseProtseqEpExA( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); +} + +/*********************************************************************** + * RpcServerUseProtseqEpW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor ) +{ + RPC_POLICY policy; + + TRACE( "(%s,%u,%s,%p)\n", debugstr_w( Protseq ), MaxCalls, debugstr_w( Endpoint ), SecurityDescriptor ); + + /* This should provide the default behaviour */ + policy.Length = sizeof( policy ); + policy.EndpointFlags = 0; + policy.NICFlags = 0; + + return RpcServerUseProtseqEpExW( Protseq, MaxCalls, Endpoint, SecurityDescriptor, &policy ); +} + +/*********************************************************************** + * alloc_serverprotoseq (internal) + * + * Must be called with server_cs held. + */ +static RPC_STATUS alloc_serverprotoseq(UINT MaxCalls, char *Protseq, RpcServerProtseq **ps) +{ + const struct protseq_ops *ops = rpcrt4_get_protseq_ops(Protseq); + + if (!ops) + { + FIXME("protseq %s not supported\n", debugstr_a(Protseq)); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + + *ps = ops->alloc(); + if (!*ps) + return RPC_S_OUT_OF_RESOURCES; + (*ps)->MaxCalls = MaxCalls; + (*ps)->Protseq = Protseq; + (*ps)->ops = ops; + (*ps)->MaxCalls = 0; + (*ps)->conn = NULL; + InitializeCriticalSection(&(*ps)->cs); + (*ps)->is_listening = FALSE; + (*ps)->mgr_mutex = NULL; + (*ps)->server_ready_event = NULL; + + list_add_head(&protseqs, &(*ps)->entry); + + TRACE("new protseq %p created for %s\n", *ps, Protseq); + + return RPC_S_OK; +} + +/* Finds a given protseq or creates a new one if one doesn't already exist */ +static RPC_STATUS RPCRT4_get_or_create_serverprotseq(UINT MaxCalls, char *Protseq, RpcServerProtseq **ps) +{ + RPC_STATUS status; + RpcServerProtseq *cps; + + EnterCriticalSection(&server_cs); + + LIST_FOR_EACH_ENTRY(cps, &protseqs, RpcServerProtseq, entry) + if (!strcmp(cps->Protseq, Protseq)) + { + TRACE("found existing protseq object for %s\n", Protseq); + *ps = cps; + LeaveCriticalSection(&server_cs); + return S_OK; + } + + status = alloc_serverprotoseq(MaxCalls, Protseq, ps); + + LeaveCriticalSection(&server_cs); + + return status; +} + +/*********************************************************************** + * RpcServerUseProtseqEpExA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpExA( RPC_CSTR Protseq, UINT MaxCalls, RPC_CSTR Endpoint, LPVOID SecurityDescriptor, + PRPC_POLICY lpPolicy ) +{ + char *szps = (char*)Protseq, *szep = (char*)Endpoint; + RpcServerProtseq* ps; + RPC_STATUS status; + + TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_a(szps), MaxCalls, + debugstr_a(szep), SecurityDescriptor, + lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); + + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, RPCRT4_strdupA(szps), &ps); + if (status != RPC_S_OK) + return status; + + return RPCRT4_use_protseq(ps, szep); +} + +/*********************************************************************** + * RpcServerUseProtseqEpExW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqEpExW( RPC_WSTR Protseq, UINT MaxCalls, RPC_WSTR Endpoint, LPVOID SecurityDescriptor, + PRPC_POLICY lpPolicy ) +{ + RpcServerProtseq* ps; + RPC_STATUS status; + LPSTR EndpointA; + + TRACE("(%s,%u,%s,%p,{%u,%lu,%lu})\n", debugstr_w( Protseq ), MaxCalls, + debugstr_w( Endpoint ), SecurityDescriptor, + lpPolicy->Length, lpPolicy->EndpointFlags, lpPolicy->NICFlags ); + + status = RPCRT4_get_or_create_serverprotseq(MaxCalls, RPCRT4_strdupWtoA(Protseq), &ps); + if (status != RPC_S_OK) + return status; + + EndpointA = RPCRT4_strdupWtoA(Endpoint); + status = RPCRT4_use_protseq(ps, EndpointA); + RPCRT4_strfree(EndpointA); + return status; +} + +/*********************************************************************** + * RpcServerUseProtseqA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqA(RPC_CSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +{ + TRACE("(Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_a((char*)Protseq), MaxCalls, SecurityDescriptor); + return RpcServerUseProtseqEpA(Protseq, MaxCalls, NULL, SecurityDescriptor); +} + +/*********************************************************************** + * RpcServerUseProtseqW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUseProtseqW(RPC_WSTR Protseq, unsigned int MaxCalls, void *SecurityDescriptor) +{ + TRACE("Protseq == %s, MaxCalls == %d, SecurityDescriptor == ^%p)\n", debugstr_w(Protseq), MaxCalls, SecurityDescriptor); + return RpcServerUseProtseqEpW(Protseq, MaxCalls, NULL, SecurityDescriptor); +} + +/*********************************************************************** + * RpcServerRegisterIf (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv ) +{ + TRACE("(%p,%s,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv); + return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, 0, RPC_C_LISTEN_MAX_CALLS_DEFAULT, (UINT)-1, NULL ); +} + +/*********************************************************************** + * RpcServerRegisterIfEx (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, + UINT Flags, UINT MaxCalls, RPC_IF_CALLBACK_FN* IfCallbackFn ) +{ + TRACE("(%p,%s,%p,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, IfCallbackFn); + return RpcServerRegisterIf2( IfSpec, MgrTypeUuid, MgrEpv, Flags, MaxCalls, (UINT)-1, IfCallbackFn ); +} + +/*********************************************************************** + * RpcServerRegisterIf2 (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterIf2( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, RPC_MGR_EPV* MgrEpv, + UINT Flags, UINT MaxCalls, UINT MaxRpcSize, RPC_IF_CALLBACK_FN* IfCallbackFn ) +{ + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + RpcServerInterface* sif; + unsigned int i; + + TRACE("(%p,%s,%p,%u,%u,%u,%p)\n", IfSpec, debugstr_guid(MgrTypeUuid), MgrEpv, Flags, MaxCalls, + MaxRpcSize, IfCallbackFn); + TRACE(" interface id: %s %d.%d\n", debugstr_guid(&If->InterfaceId.SyntaxGUID), + If->InterfaceId.SyntaxVersion.MajorVersion, + If->InterfaceId.SyntaxVersion.MinorVersion); + TRACE(" transfer syntax: %s %d.%d\n", debugstr_guid(&If->TransferSyntax.SyntaxGUID), + If->TransferSyntax.SyntaxVersion.MajorVersion, + If->TransferSyntax.SyntaxVersion.MinorVersion); + TRACE(" dispatch table: %p\n", If->DispatchTable); + if (If->DispatchTable) { + TRACE(" dispatch table count: %d\n", If->DispatchTable->DispatchTableCount); + for (i=0; iDispatchTable->DispatchTableCount; i++) { + TRACE(" entry %d: %p\n", i, If->DispatchTable->DispatchTable[i]); + } + TRACE(" reserved: %ld\n", If->DispatchTable->Reserved); + } + TRACE(" protseq endpoint count: %d\n", If->RpcProtseqEndpointCount); + TRACE(" default manager epv: %p\n", If->DefaultManagerEpv); + TRACE(" interpreter info: %p\n", If->InterpreterInfo); + + sif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcServerInterface)); + sif->If = If; + if (MgrTypeUuid) { + memcpy(&sif->MgrTypeUuid, MgrTypeUuid, sizeof(UUID)); + sif->MgrEpv = MgrEpv; + } else { + memset(&sif->MgrTypeUuid, 0, sizeof(UUID)); + sif->MgrEpv = If->DefaultManagerEpv; + } + sif->Flags = Flags; + sif->MaxCalls = MaxCalls; + sif->MaxRpcSize = MaxRpcSize; + sif->IfCallbackFn = IfCallbackFn; + + EnterCriticalSection(&server_cs); + list_add_head(&server_interfaces, &sif->entry); + LeaveCriticalSection(&server_cs); + + if (sif->Flags & RPC_IF_AUTOLISTEN) + RPCRT4_start_listen(TRUE); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerUnregisterIf (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUnregisterIf( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, UINT WaitForCallsToComplete ) +{ + PRPC_SERVER_INTERFACE If = (PRPC_SERVER_INTERFACE)IfSpec; + HANDLE event = NULL; + BOOL found = FALSE; + BOOL completed = TRUE; + RpcServerInterface *cif; + RPC_STATUS status; + + TRACE("(IfSpec == (RPC_IF_HANDLE)^%p (%s), MgrTypeUuid == %s, WaitForCallsToComplete == %u)\n", + IfSpec, debugstr_guid(&If->InterfaceId.SyntaxGUID), debugstr_guid(MgrTypeUuid), WaitForCallsToComplete); + + EnterCriticalSection(&server_cs); + LIST_FOR_EACH_ENTRY(cif, &server_interfaces, RpcServerInterface, entry) { + if ((!IfSpec || !memcmp(&If->InterfaceId, &cif->If->InterfaceId, sizeof(RPC_SYNTAX_IDENTIFIER))) && + UuidEqual(MgrTypeUuid, &cif->MgrTypeUuid, &status)) { + list_remove(&cif->entry); + if (cif->CurrentCalls) { + completed = FALSE; + if (WaitForCallsToComplete) + cif->CallsCompletedEvent = event = CreateEventW(NULL, FALSE, FALSE, NULL); + } + found = TRUE; + break; + } + } + LeaveCriticalSection(&server_cs); + + if (!found) { + ERR("not found for object %s\n", debugstr_guid(MgrTypeUuid)); + return RPC_S_UNKNOWN_IF; + } + + if (completed) + HeapFree(GetProcessHeap(), 0, cif); + else if (event) { + /* sif will be freed when the last call is completed, so be careful not to + * touch that memory here as that could happen before we get here */ + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerUnregisterIfEx (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerUnregisterIfEx( RPC_IF_HANDLE IfSpec, UUID* MgrTypeUuid, int RundownContextHandles ) +{ + FIXME("(IfSpec == (RPC_IF_HANDLE)^%p, MgrTypeUuid == %s, RundownContextHandles == %d): stub\n", + IfSpec, debugstr_guid(MgrTypeUuid), RundownContextHandles); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcObjectSetType (RPCRT4.@) + * + * PARAMS + * ObjUuid [I] "Object" UUID + * TypeUuid [I] "Type" UUID + * + * RETURNS + * RPC_S_OK The call succeeded + * RPC_S_INVALID_OBJECT The provided object (nil) is not valid + * RPC_S_ALREADY_REGISTERED The provided object is already registered + * + * Maps "Object" UUIDs to "Type" UUID's. Passing the nil UUID as the type + * resets the mapping for the specified object UUID to nil (the default). + * The nil object is always associated with the nil type and cannot be + * reassigned. Servers can support multiple implementations on the same + * interface by registering different end-point vectors for the different + * types. There's no need to call this if a server only supports the nil + * type, as is typical. + */ +RPC_STATUS WINAPI RpcObjectSetType( UUID* ObjUuid, UUID* TypeUuid ) +{ + RpcObjTypeMap *map = RpcObjTypeMaps, *prev = NULL; + RPC_STATUS dummy; + + TRACE("(ObjUUID == %s, TypeUuid == %s).\n", debugstr_guid(ObjUuid), debugstr_guid(TypeUuid)); + if ((! ObjUuid) || UuidIsNil(ObjUuid, &dummy)) { + /* nil uuid cannot be remapped */ + return RPC_S_INVALID_OBJECT; + } + + /* find the mapping for this object if there is one ... */ + while (map) { + if (! UuidCompare(ObjUuid, &map->Object, &dummy)) break; + prev = map; + map = map->next; + } + if ((! TypeUuid) || UuidIsNil(TypeUuid, &dummy)) { + /* ... and drop it from the list */ + if (map) { + if (prev) + prev->next = map->next; + else + RpcObjTypeMaps = map->next; + HeapFree(GetProcessHeap(), 0, map); + } + } else { + /* ... , fail if we found it ... */ + if (map) + return RPC_S_ALREADY_REGISTERED; + /* ... otherwise create a new one and add it in. */ + map = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcObjTypeMap)); + memcpy(&map->Object, ObjUuid, sizeof(UUID)); + memcpy(&map->Type, TypeUuid, sizeof(UUID)); + map->next = NULL; + if (prev) + prev->next = map; /* prev is the last map in the linklist */ + else + RpcObjTypeMaps = map; + } + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcServerRegisterAuthInfoA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterAuthInfoA( RPC_CSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, + LPVOID Arg ) +{ + FIXME( "(%s,%u,%p,%p): stub\n", ServerPrincName, AuthnSvc, GetKeyFn, Arg ); + + return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ +} + +/*********************************************************************** + * RpcServerRegisterAuthInfoW (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerRegisterAuthInfoW( RPC_WSTR ServerPrincName, ULONG AuthnSvc, RPC_AUTH_KEY_RETRIEVAL_FN GetKeyFn, + LPVOID Arg ) +{ + FIXME( "(%s,%u,%p,%p): stub\n", debugstr_w( ServerPrincName ), AuthnSvc, GetKeyFn, Arg ); + + return RPC_S_UNKNOWN_AUTHN_SERVICE; /* We don't know any authentication services */ +} + +/*********************************************************************** + * RpcServerListen (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcServerListen( UINT MinimumCallThreads, UINT MaxCalls, UINT DontWait ) +{ + RPC_STATUS status = RPC_S_OK; + + TRACE("(%u,%u,%u)\n", MinimumCallThreads, MaxCalls, DontWait); + + if (list_empty(&protseqs)) + return RPC_S_NO_PROTSEQS_REGISTERED; + + status = RPCRT4_start_listen(FALSE); + + if (DontWait || (status != RPC_S_OK)) return status; + + return RpcMgmtWaitServerListen(); +} + +/*********************************************************************** + * RpcMgmtServerWaitListen (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtWaitServerListen( void ) +{ + TRACE("()\n"); + + EnterCriticalSection(&listen_cs); + + if (!std_listen) { + LeaveCriticalSection(&listen_cs); + return RPC_S_NOT_LISTENING; + } + + LeaveCriticalSection(&listen_cs); + + FIXME("not waiting for server calls to finish\n"); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcMgmtStopServerListening (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtStopServerListening ( RPC_BINDING_HANDLE Binding ) +{ + TRACE("(Binding == (RPC_BINDING_HANDLE)^%p)\n", Binding); + + if (Binding) { + FIXME("client-side invocation not implemented.\n"); + return RPC_S_WRONG_KIND_OF_BINDING; + } + + RPCRT4_stop_listen(FALSE); + + return RPC_S_OK; +} + +/*********************************************************************** + * RpcMgmtEnableIdleCleanup (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtEnableIdleCleanup(void) +{ + FIXME("(): stub\n"); + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcServerStartListening (RPCRT4.@) + */ +RPC_STATUS WINAPI I_RpcServerStartListening( HWND hWnd ) +{ + FIXME( "(%p): stub\n", hWnd ); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcServerStopListening (RPCRT4.@) + */ +RPC_STATUS WINAPI I_RpcServerStopListening( void ) +{ + FIXME( "(): stub\n" ); + + return RPC_S_OK; +} + +/*********************************************************************** + * I_RpcWindowProc (RPCRT4.@) + */ +UINT WINAPI I_RpcWindowProc( void *hWnd, UINT Message, UINT wParam, ULONG lParam ) +{ + FIXME( "(%p,%08x,%08x,%08x): stub\n", hWnd, Message, wParam, lParam ); + + return 0; +} + +/*********************************************************************** + * RpcMgmtInqIfIds (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtInqIfIds(RPC_BINDING_HANDLE Binding, RPC_IF_ID_VECTOR **IfIdVector) +{ + FIXME("(%p,%p): stub\n", Binding, IfIdVector); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcMgmtEpEltInqBegin (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtEpEltInqBegin(RPC_BINDING_HANDLE Binding, ULONG InquiryType, + RPC_IF_ID *IfId, ULONG VersOption, UUID *ObjectUuid, RPC_EP_INQ_HANDLE* InquiryContext) +{ + FIXME("(%p,%u,%p,%u,%p,%p): stub\n", + Binding, InquiryType, IfId, VersOption, ObjectUuid, InquiryContext); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcMgmtIsServerListening (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtIsServerListening(RPC_BINDING_HANDLE Binding) +{ + FIXME("(%p): stub\n", Binding); + return RPC_S_INVALID_BINDING; +} + +/*********************************************************************** + * RpcMgmtSetServerStackSize (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcMgmtSetServerStackSize(ULONG ThreadStackSize) +{ + FIXME("(0x%x): stub\n", ThreadStackSize); + return RPC_S_OK; +} diff --git a/reactos/dll/win32/rpcrt4_new/rpc_server.h b/reactos/dll/win32/rpcrt4_new/rpc_server.h new file mode 100644 index 00000000000..eb32be6afc9 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_server.h @@ -0,0 +1,81 @@ +/* + * RPC server API + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * + * 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 + */ + +#ifndef __WINE_RPC_SERVER_H +#define __WINE_RPC_SERVER_H + +#include "rpc_binding.h" +#include "wine/list.h" + +struct protseq_ops; + +typedef struct _RpcServerProtseq +{ + const struct protseq_ops *ops; /* RO */ + struct list entry; /* CS ::server_cs */ + LPSTR Protseq; /* RO */ + UINT MaxCalls; /* RO */ + /* list of listening connections */ + RpcConnection* conn; /* CS cs */ + CRITICAL_SECTION cs; + + /* is the server currently listening? */ + BOOL is_listening; /* CS ::listen_cs */ + /* mutex for ensuring only one thread can change state at a time */ + HANDLE mgr_mutex; + /* set when server thread has finished opening connections */ + HANDLE server_ready_event; +} RpcServerProtseq; + +struct protseq_ops +{ + const char *name; + RpcServerProtseq *(*alloc)(void); + void (*signal_state_changed)(RpcServerProtseq *protseq); + /* previous array is passed in to allow reuse of memory */ + void *(*get_wait_array)(RpcServerProtseq *protseq, void *prev_array, unsigned int *count); + void (*free_wait_array)(RpcServerProtseq *protseq, void *array); + /* returns -1 for failure, 0 for server state changed and 1 to indicate a + * new connection was established */ + int (*wait_for_new_connection)(RpcServerProtseq *protseq, unsigned int count, void *wait_array); + /* opens the endpoint and optionally begins listening */ + RPC_STATUS (*open_endpoint)(RpcServerProtseq *protseq, LPSTR endpoint); +}; + +typedef struct _RpcServerInterface +{ + struct list entry; + RPC_SERVER_INTERFACE* If; + UUID MgrTypeUuid; + RPC_MGR_EPV* MgrEpv; + UINT Flags; + UINT MaxCalls; + UINT MaxRpcSize; + RPC_IF_CALLBACK_FN* IfCallbackFn; + LONG CurrentCalls; /* number of calls currently executing */ + /* set when unregistering interface to let the caller of + * RpcServerUnregisterIf* know that all calls have finished */ + HANDLE CallsCompletedEvent; +} RpcServerInterface; + +void RPCRT4_new_client(RpcConnection* conn); +const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq); + +#endif /* __WINE_RPC_SERVER_H */ diff --git a/reactos/dll/win32/rpcrt4_new/rpc_transport.c b/reactos/dll/win32/rpcrt4_new/rpc_transport.c new file mode 100644 index 00000000000..071ccb99973 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpc_transport.c @@ -0,0 +1,1760 @@ +/* + * RPC transport layer + * + * Copyright 2001 Ove Kåven, TransGaming Technologies + * Copyright 2003 Mike Hearn + * Copyright 2004 Filip Navara + * Copyright 2006 Mike McCormack + * Copyright 2006 Damjan Jovanovic + * + * 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 "config.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_NETINET_TCP_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_SYS_POLL_H +#include +#endif + +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "winnls.h" +#include "winerror.h" +#include "winternl.h" +#include "wine/unicode.h" + +#include "rpc.h" +#include "rpcndr.h" + +#include "wine/debug.h" + +#include "rpc_binding.h" +#include "rpc_message.h" +#include "rpc_server.h" +#include "epm_towers.h" + +#include "unix_func.h" + +#ifndef SOL_TCP +# define SOL_TCP IPPROTO_TCP +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +static CRITICAL_SECTION assoc_list_cs; +static CRITICAL_SECTION_DEBUG assoc_list_cs_debug = +{ + 0, 0, &assoc_list_cs, + { &assoc_list_cs_debug.ProcessLocksList, &assoc_list_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": assoc_list_cs") } +}; +static CRITICAL_SECTION assoc_list_cs = { &assoc_list_cs_debug, -1, 0, 0, 0, 0 }; + +static struct list assoc_list = LIST_INIT(assoc_list); + +/**** ncacn_np support ****/ + +typedef struct _RpcConnection_np +{ + RpcConnection common; + HANDLE pipe; + OVERLAPPED ovl; + BOOL listening; +} RpcConnection_np; + +static RpcConnection *rpcrt4_conn_np_alloc(void) +{ + RpcConnection_np *npc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_np)); + if (npc) + { + npc->pipe = NULL; + memset(&npc->ovl, 0, sizeof(npc->ovl)); + npc->listening = FALSE; + } + return &npc->common; +} + +static RPC_STATUS rpcrt4_conn_listen_pipe(RpcConnection_np *npc) +{ + if (npc->listening) + return RPC_S_OK; + + npc->listening = TRUE; + if (ConnectNamedPipe(npc->pipe, &npc->ovl)) + return RPC_S_OK; + + if (GetLastError() == ERROR_PIPE_CONNECTED) { + SetEvent(npc->ovl.hEvent); + return RPC_S_OK; + } + if (GetLastError() == ERROR_IO_PENDING) { + /* will be completed in rpcrt4_protseq_np_wait_for_new_connection */ + return RPC_S_OK; + } + npc->listening = FALSE; + WARN("Couldn't ConnectNamedPipe (error was %d)\n", GetLastError()); + return RPC_S_OUT_OF_RESOURCES; +} + +static RPC_STATUS rpcrt4_conn_create_pipe(RpcConnection *Connection, LPCSTR pname) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + TRACE("listening on %s\n", pname); + + npc->pipe = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, + PIPE_UNLIMITED_INSTANCES, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL); + if (npc->pipe == INVALID_HANDLE_VALUE) { + WARN("CreateNamedPipe failed with error %d\n", GetLastError()); + if (GetLastError() == ERROR_FILE_EXISTS) + return RPC_S_DUPLICATE_ENDPOINT; + else + return RPC_S_CANT_CREATE_ENDPOINT; + } + + memset(&npc->ovl, 0, sizeof(npc->ovl)); + npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + + /* Note: we don't call ConnectNamedPipe here because it must be done in the + * server thread as the thread must be alertable */ + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_conn_open_pipe(RpcConnection *Connection, LPCSTR pname, BOOL wait) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + HANDLE pipe; + DWORD err, dwMode; + + TRACE("connecting to %s\n", pname); + + while (TRUE) { + DWORD dwFlags = 0; + if (Connection->QOS) + { + dwFlags = SECURITY_SQOS_PRESENT; + switch (Connection->QOS->qos->ImpersonationType) + { + case RPC_C_IMP_LEVEL_DEFAULT: + /* FIXME: what to do here? */ + break; + case RPC_C_IMP_LEVEL_ANONYMOUS: + dwFlags |= SECURITY_ANONYMOUS; + break; + case RPC_C_IMP_LEVEL_IDENTIFY: + dwFlags |= SECURITY_IDENTIFICATION; + break; + case RPC_C_IMP_LEVEL_IMPERSONATE: + dwFlags |= SECURITY_IMPERSONATION; + break; + case RPC_C_IMP_LEVEL_DELEGATE: + dwFlags |= SECURITY_DELEGATION; + break; + } + if (Connection->QOS->qos->IdentityTracking == RPC_C_QOS_IDENTIFY_DYNAMIC) + dwFlags |= SECURITY_CONTEXT_TRACKING; + } + pipe = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, dwFlags, 0); + if (pipe != INVALID_HANDLE_VALUE) break; + err = GetLastError(); + if (err == ERROR_PIPE_BUSY) { + TRACE("connection failed, error=%x\n", err); + return RPC_S_SERVER_TOO_BUSY; + } + if (!wait) + return RPC_S_SERVER_UNAVAILABLE; + if (!WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) { + err = GetLastError(); + WARN("connection failed, error=%x\n", err); + return RPC_S_SERVER_UNAVAILABLE; + } + } + + /* success */ + memset(&npc->ovl, 0, sizeof(npc->ovl)); + /* pipe is connected; change to message-read mode. */ + dwMode = PIPE_READMODE_MESSAGE; + SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL); + npc->ovl.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + npc->pipe = pipe; + + return RPC_S_OK; +} + +static RPC_STATUS rpcrt4_ncalrpc_open(RpcConnection* Connection) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; + RPC_STATUS r; + LPSTR pname; + + /* already connected? */ + if (npc->pipe) + return RPC_S_OK; + + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_open_pipe(Connection, pname, TRUE); + I_RpcFree(pname); + + return r; +} + +static RPC_STATUS rpcrt4_protseq_ncalrpc_open_endpoint(RpcServerProtseq* protseq, LPSTR endpoint) +{ + static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; + RPC_STATUS r; + LPSTR pname; + RpcConnection *Connection; + + r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, + endpoint, NULL, NULL, NULL); + if (r != RPC_S_OK) + return r; + + /* protseq=ncalrpc: supposed to use NT LPC ports, + * but we'll implement it with named pipes for now */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_create_pipe(Connection, pname); + I_RpcFree(pname); + + EnterCriticalSection(&protseq->cs); + Connection->Next = protseq->conn; + protseq->conn = Connection; + LeaveCriticalSection(&protseq->cs); + + return r; +} + +static RPC_STATUS rpcrt4_ncacn_np_open(RpcConnection* Connection) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + static const char prefix[] = "\\\\."; + RPC_STATUS r; + LPSTR pname; + + /* already connected? */ + if (npc->pipe) + return RPC_S_OK; + + /* protseq=ncacn_np: named pipes */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_open_pipe(Connection, pname, FALSE); + I_RpcFree(pname); + + return r; +} + +static RPC_STATUS rpcrt4_protseq_ncacn_np_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint) +{ + static const char prefix[] = "\\\\."; + RPC_STATUS r; + LPSTR pname; + RpcConnection *Connection; + + r = RPCRT4_CreateConnection(&Connection, TRUE, protseq->Protseq, NULL, + endpoint, NULL, NULL, NULL); + if (r != RPC_S_OK) + return r; + + /* protseq=ncacn_np: named pipes */ + pname = I_RpcAllocate(strlen(prefix) + strlen(Connection->Endpoint) + 1); + strcat(strcpy(pname, prefix), Connection->Endpoint); + r = rpcrt4_conn_create_pipe(Connection, pname); + I_RpcFree(pname); + + EnterCriticalSection(&protseq->cs); + Connection->Next = protseq->conn; + protseq->conn = Connection; + LeaveCriticalSection(&protseq->cs); + + return r; +} + +static void rpcrt4_conn_np_handoff(RpcConnection_np *old_npc, RpcConnection_np *new_npc) +{ + /* because of the way named pipes work, we'll transfer the connected pipe + * to the child, then reopen the server binding to continue listening */ + + new_npc->pipe = old_npc->pipe; + new_npc->ovl = old_npc->ovl; + old_npc->pipe = 0; + memset(&old_npc->ovl, 0, sizeof(old_npc->ovl)); + old_npc->listening = FALSE; +} + +static RPC_STATUS rpcrt4_ncacn_np_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + RPC_STATUS status; + LPSTR pname; + static const char prefix[] = "\\\\."; + + rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); + + pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1); + strcat(strcpy(pname, prefix), old_conn->Endpoint); + status = rpcrt4_conn_create_pipe(old_conn, pname); + I_RpcFree(pname); + + return status; +} + +static RPC_STATUS rpcrt4_ncalrpc_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + RPC_STATUS status; + LPSTR pname; + static const char prefix[] = "\\\\.\\pipe\\lrpc\\"; + + TRACE("%s\n", old_conn->Endpoint); + + rpcrt4_conn_np_handoff((RpcConnection_np *)old_conn, (RpcConnection_np *)new_conn); + + pname = I_RpcAllocate(strlen(prefix) + strlen(old_conn->Endpoint) + 1); + strcat(strcpy(pname, prefix), old_conn->Endpoint); + status = rpcrt4_conn_create_pipe(old_conn, pname); + I_RpcFree(pname); + + return status; +} + +static int rpcrt4_conn_np_read(RpcConnection *Connection, + void *buffer, unsigned int count) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + char *buf = buffer; + BOOL ret = TRUE; + unsigned int bytes_left = count; + + while (bytes_left) + { + DWORD bytes_read; + ret = ReadFile(npc->pipe, buf, bytes_left, &bytes_read, NULL); + if (!ret || !bytes_read) + break; + bytes_left -= bytes_read; + buf += bytes_read; + } + return ret ? count : -1; +} + +static int rpcrt4_conn_np_write(RpcConnection *Connection, + const void *buffer, unsigned int count) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + const char *buf = buffer; + BOOL ret = TRUE; + unsigned int bytes_left = count; + + while (bytes_left) + { + DWORD bytes_written; + ret = WriteFile(npc->pipe, buf, count, &bytes_written, NULL); + if (!ret || !bytes_written) + break; + bytes_left -= bytes_written; + buf += bytes_written; + } + return ret ? count : -1; +} + +static int rpcrt4_conn_np_close(RpcConnection *Connection) +{ + RpcConnection_np *npc = (RpcConnection_np *) Connection; + if (npc->pipe) { + FlushFileBuffers(npc->pipe); + CloseHandle(npc->pipe); + npc->pipe = 0; + } + if (npc->ovl.hEvent) { + CloseHandle(npc->ovl.hEvent); + npc->ovl.hEvent = 0; + } + return 0; +} + +static size_t rpcrt4_ncacn_np_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + twr_empty_floor_t *smb_floor; + twr_empty_floor_t *nb_floor; + size_t size; + size_t networkaddr_size; + size_t endpoint_size; + + TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); + + networkaddr_size = strlen(networkaddr) + 1; + endpoint_size = strlen(endpoint) + 1; + size = sizeof(*smb_floor) + endpoint_size + sizeof(*nb_floor) + networkaddr_size; + + if (!tower_data) + return size; + + smb_floor = (twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*smb_floor); + + smb_floor->count_lhs = sizeof(smb_floor->protid); + smb_floor->protid = EPM_PROTOCOL_SMB; + smb_floor->count_rhs = endpoint_size; + + memcpy(tower_data, endpoint, endpoint_size); + tower_data += endpoint_size; + + nb_floor = (twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*nb_floor); + + nb_floor->count_lhs = sizeof(nb_floor->protid); + nb_floor->protid = EPM_PROTOCOL_NETBIOS; + nb_floor->count_rhs = networkaddr_size; + + memcpy(tower_data, networkaddr, networkaddr_size); + tower_data += networkaddr_size; + + return size; +} + +static RPC_STATUS rpcrt4_ncacn_np_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + const twr_empty_floor_t *smb_floor = (const twr_empty_floor_t *)tower_data; + const twr_empty_floor_t *nb_floor; + + TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); + + if (tower_size < sizeof(*smb_floor)) + return EPT_S_NOT_REGISTERED; + + tower_data += sizeof(*smb_floor); + tower_size -= sizeof(*smb_floor); + + if ((smb_floor->count_lhs != sizeof(smb_floor->protid)) || + (smb_floor->protid != EPM_PROTOCOL_SMB) || + (smb_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + + if (endpoint) + { + *endpoint = I_RpcAllocate(smb_floor->count_rhs); + if (!*endpoint) + return RPC_S_OUT_OF_RESOURCES; + memcpy(*endpoint, tower_data, smb_floor->count_rhs); + } + tower_data += smb_floor->count_rhs; + tower_size -= smb_floor->count_rhs; + + if (tower_size < sizeof(*nb_floor)) + return EPT_S_NOT_REGISTERED; + + nb_floor = (const twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*nb_floor); + tower_size -= sizeof(*nb_floor); + + if ((nb_floor->count_lhs != sizeof(nb_floor->protid)) || + (nb_floor->protid != EPM_PROTOCOL_NETBIOS) || + (nb_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + + if (networkaddr) + { + *networkaddr = I_RpcAllocate(nb_floor->count_rhs); + if (!*networkaddr) + { + if (endpoint) + { + I_RpcFree(*endpoint); + *endpoint = NULL; + } + return RPC_S_OUT_OF_RESOURCES; + } + memcpy(*networkaddr, tower_data, nb_floor->count_rhs); + } + + return RPC_S_OK; +} + +typedef struct _RpcServerProtseq_np +{ + RpcServerProtseq common; + HANDLE mgr_event; +} RpcServerProtseq_np; + +static RpcServerProtseq *rpcrt4_protseq_np_alloc(void) +{ + RpcServerProtseq_np *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps)); + if (ps) + ps->mgr_event = CreateEventW(NULL, FALSE, FALSE, NULL); + return &ps->common; +} + +static void rpcrt4_protseq_np_signal_state_changed(RpcServerProtseq *protseq) +{ + RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common); + SetEvent(npps->mgr_event); +} + +static void *rpcrt4_protseq_np_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) +{ + HANDLE *objs = prev_array; + RpcConnection_np *conn; + RpcServerProtseq_np *npps = CONTAINING_RECORD(protseq, RpcServerProtseq_np, common); + + EnterCriticalSection(&protseq->cs); + + /* open and count connections */ + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common); + while (conn) { + rpcrt4_conn_listen_pipe(conn); + if (conn->ovl.hEvent) + (*count)++; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common); + } + + /* make array of connections */ + if (objs) + objs = HeapReAlloc(GetProcessHeap(), 0, objs, *count*sizeof(HANDLE)); + else + objs = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(HANDLE)); + if (!objs) + { + ERR("couldn't allocate objs\n"); + LeaveCriticalSection(&protseq->cs); + return NULL; + } + + objs[0] = npps->mgr_event; + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common); + while (conn) { + if ((objs[*count] = conn->ovl.hEvent)) + (*count)++; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common); + } + LeaveCriticalSection(&protseq->cs); + return objs; +} + +static void rpcrt4_protseq_np_free_wait_array(RpcServerProtseq *protseq, void *array) +{ + HeapFree(GetProcessHeap(), 0, array); +} + +static int rpcrt4_protseq_np_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) +{ + HANDLE b_handle; + HANDLE *objs = wait_array; + DWORD res; + RpcConnection *cconn; + RpcConnection_np *conn; + + if (!objs) + return -1; + + res = WaitForMultipleObjects(count, objs, FALSE, INFINITE); + if (res == WAIT_OBJECT_0) + return 0; + else if (res == WAIT_FAILED) + { + ERR("wait failed with error %d\n", GetLastError()); + return -1; + } + else + { + b_handle = objs[res - WAIT_OBJECT_0]; + /* find which connection got a RPC */ + EnterCriticalSection(&protseq->cs); + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_np, common); + while (conn) { + if (b_handle == conn->ovl.hEvent) break; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_np, common); + } + cconn = NULL; + if (conn) + RPCRT4_SpawnConnection(&cconn, &conn->common); + else + ERR("failed to locate connection for handle %p\n", b_handle); + LeaveCriticalSection(&protseq->cs); + if (cconn) + { + RPCRT4_new_client(cconn); + return 1; + } + else return -1; + } +} + +static size_t rpcrt4_ncalrpc_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + twr_empty_floor_t *pipe_floor; + size_t size; + size_t endpoint_size; + + TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); + + endpoint_size = strlen(networkaddr) + 1; + size = sizeof(*pipe_floor) + endpoint_size; + + if (!tower_data) + return size; + + pipe_floor = (twr_empty_floor_t *)tower_data; + + tower_data += sizeof(*pipe_floor); + + pipe_floor->count_lhs = sizeof(pipe_floor->protid); + pipe_floor->protid = EPM_PROTOCOL_SMB; + pipe_floor->count_rhs = endpoint_size; + + memcpy(tower_data, endpoint, endpoint_size); + tower_data += endpoint_size; + + return size; +} + +static RPC_STATUS rpcrt4_ncalrpc_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + const twr_empty_floor_t *pipe_floor = (const twr_empty_floor_t *)tower_data; + + TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); + + *networkaddr = NULL; + *endpoint = NULL; + + if (tower_size < sizeof(*pipe_floor)) + return EPT_S_NOT_REGISTERED; + + tower_data += sizeof(*pipe_floor); + tower_size -= sizeof(*pipe_floor); + + if ((pipe_floor->count_lhs != sizeof(pipe_floor->protid)) || + (pipe_floor->protid != EPM_PROTOCOL_SMB) || + (pipe_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + + if (endpoint) + { + *endpoint = I_RpcAllocate(pipe_floor->count_rhs); + if (!*endpoint) + return RPC_S_OUT_OF_RESOURCES; + memcpy(*endpoint, tower_data, pipe_floor->count_rhs); + } + + return RPC_S_OK; +} + +/**** ncacn_ip_tcp support ****/ + +typedef struct _RpcConnection_tcp +{ + RpcConnection common; + int sock; +} RpcConnection_tcp; + +static RpcConnection *rpcrt4_conn_tcp_alloc(void) +{ + RpcConnection_tcp *tcpc; + tcpc = HeapAlloc(GetProcessHeap(), 0, sizeof(RpcConnection_tcp)); + if (tcpc == NULL) + return NULL; + tcpc->sock = -1; + return &tcpc->common; +} + +static RPC_STATUS rpcrt4_ncacn_ip_tcp_open(RpcConnection* Connection) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + int sock; + int ret; + struct addrinfo *ai; + struct addrinfo *ai_cur; + struct addrinfo hints; + + TRACE("(%s, %s)\n", Connection->NetworkAddr, Connection->Endpoint); + + if (tcpc->sock != -1) + return RPC_S_OK; + + hints.ai_flags = 0; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + ret = getaddrinfo(Connection->NetworkAddr, Connection->Endpoint, &hints, &ai); + if (ret) + { + ERR("getaddrinfo for %s:%s failed: %s\n", Connection->NetworkAddr, + Connection->Endpoint, gai_strerror(ret)); + return RPC_S_SERVER_UNAVAILABLE; + } + + for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) + { + int val; + + if (TRACE_ON(rpc)) + { + char host[256]; + char service[256]; + getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST | NI_NUMERICSERV); + TRACE("trying %s:%s\n", host, service); + } + + sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); + if (sock < 0) + { + WARN("socket() failed: %s\n", strerror(errno)); + continue; + } + + if (0>connect(sock, ai_cur->ai_addr, ai_cur->ai_addrlen)) + { + WARN("connect() failed: %s\n", strerror(errno)); + close(sock); + continue; + } + + /* RPC depends on having minimal latency so disable the Nagle algorithm */ + val = 1; + setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); + + tcpc->sock = sock; + + freeaddrinfo(ai); + TRACE("connected\n"); + return RPC_S_OK; + } + + freeaddrinfo(ai); + ERR("couldn't connect to %s:%s\n", Connection->NetworkAddr, Connection->Endpoint); + return RPC_S_SERVER_UNAVAILABLE; +} + +static RPC_STATUS rpcrt4_protseq_ncacn_ip_tcp_open_endpoint(RpcServerProtseq *protseq, LPSTR endpoint) +{ + RPC_STATUS status = RPC_S_CANT_CREATE_ENDPOINT; + int sock; + int ret; + struct addrinfo *ai; + struct addrinfo *ai_cur; + struct addrinfo hints; + RpcConnection *first_connection = NULL; + u_long blocking; + + TRACE("(%p, %s)\n", protseq, endpoint); + + hints.ai_flags = AI_PASSIVE /* for non-localhost addresses */; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + ret = getaddrinfo(NULL, endpoint, &hints, &ai); + if (ret) + { + ERR("getaddrinfo for port %s failed: %s\n", endpoint, + gai_strerror(ret)); + if ((ret == EAI_SERVICE) || (ret == EAI_NONAME)) + return RPC_S_INVALID_ENDPOINT_FORMAT; + return RPC_S_CANT_CREATE_ENDPOINT; + } + + for (ai_cur = ai; ai_cur; ai_cur = ai_cur->ai_next) + { + RpcConnection_tcp *tcpc; + RPC_STATUS create_status; + + if (TRACE_ON(rpc)) + { + char host[256]; + char service[256]; + getnameinfo(ai_cur->ai_addr, ai_cur->ai_addrlen, + host, sizeof(host), service, sizeof(service), + NI_NUMERICHOST | NI_NUMERICSERV); + TRACE("trying %s:%s\n", host, service); + } + + sock = socket(ai_cur->ai_family, ai_cur->ai_socktype, ai_cur->ai_protocol); + if (sock < 0) + { + WARN("socket() failed: %s\n", strerror(errno)); + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + + ret = bind(sock, ai_cur->ai_addr, ai_cur->ai_addrlen); + if (ret < 0) + { + WARN("bind failed: %s\n", strerror(errno)); + close(sock); + if (errno == WSAEADDRINUSE) + status = RPC_S_DUPLICATE_ENDPOINT; + else + status = RPC_S_CANT_CREATE_ENDPOINT; + continue; + } + create_status = RPCRT4_CreateConnection((RpcConnection **)&tcpc, TRUE, + protseq->Protseq, NULL, + endpoint, NULL, NULL, NULL); + if (create_status != RPC_S_OK) + { + close(sock); + status = create_status; + continue; + } + + tcpc->sock = sock; + ret = listen(sock, protseq->MaxCalls); + if (ret < 0) + { + WARN("listen failed: %s\n", strerror(errno)); + RPCRT4_DestroyConnection(&tcpc->common); + status = RPC_S_OUT_OF_RESOURCES; + continue; + } + /* need a non-blocking socket, otherwise accept() has a potential + * race-condition (poll() says it is readable, connection drops, + * and accept() blocks until the next connection comes...) + */ + blocking = 1; + ret = ioctlsocket(sock, FIONBIO, &blocking); + if (ret < 0) + { + WARN("couldn't make socket non-blocking, error %d\n", ret); + RPCRT4_DestroyConnection(&tcpc->common); + status = RPC_S_OUT_OF_RESOURCES; + continue; + } + + tcpc->common.Next = first_connection; + first_connection = &tcpc->common; + } + + freeaddrinfo(ai); + + /* if at least one connection was created for an endpoint then + * return success */ + if (first_connection) + { + RpcConnection *conn; + + /* find last element in list */ + for (conn = first_connection; conn->Next; conn = conn->Next) + ; + + EnterCriticalSection(&protseq->cs); + conn->Next = protseq->conn; + protseq->conn = first_connection; + LeaveCriticalSection(&protseq->cs); + + TRACE("listening on %s\n", endpoint); + return RPC_S_OK; + } + + ERR("couldn't listen on port %s\n", endpoint); + return status; +} + +static RPC_STATUS rpcrt4_conn_tcp_handoff(RpcConnection *old_conn, RpcConnection *new_conn) +{ + int ret; + struct sockaddr_in address; + socklen_t addrsize; + u_long blocking; + RpcConnection_tcp *server = (RpcConnection_tcp*) old_conn; + RpcConnection_tcp *client = (RpcConnection_tcp*) new_conn; + + addrsize = sizeof(address); + ret = accept(server->sock, (struct sockaddr*) &address, &addrsize); + if (ret < 0) + { + ERR("Failed to accept a TCP connection: error %d\n", ret); + return RPC_S_OUT_OF_RESOURCES; + } + /* reset to blocking behaviour */ + blocking = 0; + ret = ioctlsocket(ret, FIONBIO, &blocking); + client->sock = ret; + TRACE("Accepted a new TCP connection\n"); + return RPC_S_OK; +} + +static int rpcrt4_conn_tcp_read(RpcConnection *Connection, + void *buffer, unsigned int count) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + int r = recv(tcpc->sock, buffer, count, MSG_WAITALL); + TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r); + return r; +} + +static int rpcrt4_conn_tcp_write(RpcConnection *Connection, + const void *buffer, unsigned int count) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + int r = write(tcpc->sock, buffer, count); + TRACE("%d %p %u -> %d\n", tcpc->sock, buffer, count, r); + return r; +} + +static int rpcrt4_conn_tcp_close(RpcConnection *Connection) +{ + RpcConnection_tcp *tcpc = (RpcConnection_tcp *) Connection; + + TRACE("%d\n", tcpc->sock); + + if (tcpc->sock != -1) + close(tcpc->sock); + tcpc->sock = -1; + return 0; +} + +static size_t rpcrt4_ncacn_ip_tcp_get_top_of_tower(unsigned char *tower_data, + const char *networkaddr, + const char *endpoint) +{ + twr_tcp_floor_t *tcp_floor; + twr_ipv4_floor_t *ipv4_floor; + struct addrinfo *ai; + struct addrinfo hints; + int ret; + size_t size = sizeof(*tcp_floor) + sizeof(*ipv4_floor); + + TRACE("(%p, %s, %s)\n", tower_data, networkaddr, endpoint); + + if (!tower_data) + return size; + + tcp_floor = (twr_tcp_floor_t *)tower_data; + tower_data += sizeof(*tcp_floor); + + ipv4_floor = (twr_ipv4_floor_t *)tower_data; + + tcp_floor->count_lhs = sizeof(tcp_floor->protid); + tcp_floor->protid = EPM_PROTOCOL_TCP; + tcp_floor->count_rhs = sizeof(tcp_floor->port); + + ipv4_floor->count_lhs = sizeof(ipv4_floor->protid); + ipv4_floor->protid = EPM_PROTOCOL_IP; + ipv4_floor->count_rhs = sizeof(ipv4_floor->ipv4addr); + + hints.ai_flags = AI_NUMERICHOST; + /* FIXME: only support IPv4 at the moment. how is IPv6 represented by the EPM? */ + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + ret = getaddrinfo(networkaddr, endpoint, &hints, &ai); + if (ret) + { + ret = getaddrinfo("0.0.0.0", endpoint, &hints, &ai); + if (ret) + { + ERR("getaddrinfo failed: %s\n", gai_strerror(ret)); + return 0; + } + } + + if (ai->ai_family == PF_INET) + { + const struct sockaddr_in *sin = (const struct sockaddr_in *)ai->ai_addr; + tcp_floor->port = sin->sin_port; + ipv4_floor->ipv4addr = sin->sin_addr.s_addr; + } + else + { + ERR("unexpected protocol family %d\n", ai->ai_family); + return 0; + } + + freeaddrinfo(ai); + + return size; +} + +static RPC_STATUS rpcrt4_ncacn_ip_tcp_parse_top_of_tower(const unsigned char *tower_data, + size_t tower_size, + char **networkaddr, + char **endpoint) +{ + const twr_tcp_floor_t *tcp_floor = (const twr_tcp_floor_t *)tower_data; + const twr_ipv4_floor_t *ipv4_floor; + struct in_addr in_addr; + + TRACE("(%p, %d, %p, %p)\n", tower_data, (int)tower_size, networkaddr, endpoint); + + if (tower_size < sizeof(*tcp_floor)) + return EPT_S_NOT_REGISTERED; + + tower_data += sizeof(*tcp_floor); + tower_size -= sizeof(*tcp_floor); + + if (tower_size < sizeof(*ipv4_floor)) + return EPT_S_NOT_REGISTERED; + + ipv4_floor = (const twr_ipv4_floor_t *)tower_data; + + if ((tcp_floor->count_lhs != sizeof(tcp_floor->protid)) || + (tcp_floor->protid != EPM_PROTOCOL_TCP) || + (tcp_floor->count_rhs != sizeof(tcp_floor->port)) || + (ipv4_floor->count_lhs != sizeof(ipv4_floor->protid)) || + (ipv4_floor->protid != EPM_PROTOCOL_IP) || + (ipv4_floor->count_rhs != sizeof(ipv4_floor->ipv4addr))) + return EPT_S_NOT_REGISTERED; + + if (endpoint) + { + *endpoint = I_RpcAllocate(6 /* sizeof("65535") + 1 */); + if (!*endpoint) + return RPC_S_OUT_OF_RESOURCES; + sprintf(*endpoint, "%u", ntohs(tcp_floor->port)); + } + + if (networkaddr) + { + *networkaddr = I_RpcAllocate(INET_ADDRSTRLEN); + if (!*networkaddr) + { + if (endpoint) + { + I_RpcFree(*endpoint); + *endpoint = NULL; + } + return RPC_S_OUT_OF_RESOURCES; + } + in_addr.s_addr = ipv4_floor->ipv4addr; + if (!inet_ntop(AF_INET, &in_addr, *networkaddr, INET_ADDRSTRLEN)) + { + ERR("inet_ntop: %s\n", strerror(errno)); + I_RpcFree(*networkaddr); + *networkaddr = NULL; + if (endpoint) + { + I_RpcFree(*endpoint); + *endpoint = NULL; + } + return EPT_S_NOT_REGISTERED; + } + } + + return RPC_S_OK; +} + +typedef struct _RpcServerProtseq_sock +{ + RpcServerProtseq common; + int mgr_event_rcv; + int mgr_event_snd; +} RpcServerProtseq_sock; + +static RpcServerProtseq *rpcrt4_protseq_sock_alloc(void) +{ + RpcServerProtseq_sock *ps = HeapAlloc(GetProcessHeap(), 0, sizeof(*ps)); + if (ps) + { + int fds[2]; + u_long blocking; + if (!socketpair(PF_UNIX, SOCK_DGRAM, 0, fds)) + { + blocking = 1; + ioctlsocket(fds[0], FIONBIO, &blocking); + ioctlsocket(fds[1], FIONBIO, &blocking); + ps->mgr_event_rcv = fds[0]; + ps->mgr_event_snd = fds[1]; + } + else + { + ERR("socketpair failed with error %s\n", strerror(errno)); + HeapFree(GetProcessHeap(), 0, ps); + return NULL; + } + } + return &ps->common; +} + +static void rpcrt4_protseq_sock_signal_state_changed(RpcServerProtseq *protseq) +{ + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + char dummy = 1; + write(sockps->mgr_event_snd, &dummy, sizeof(dummy)); +} + +static void *rpcrt4_protseq_sock_get_wait_array(RpcServerProtseq *protseq, void *prev_array, unsigned int *count) +{ + struct pollfd *poll_info = prev_array; + RpcConnection_tcp *conn; + RpcServerProtseq_sock *sockps = CONTAINING_RECORD(protseq, RpcServerProtseq_sock, common); + + EnterCriticalSection(&protseq->cs); + + /* open and count connections */ + *count = 1; + conn = (RpcConnection_tcp *)protseq->conn; + while (conn) { + if (conn->sock != -1) + (*count)++; + conn = (RpcConnection_tcp *)conn->common.Next; + } + + /* make array of connections */ + if (poll_info) + poll_info = HeapReAlloc(GetProcessHeap(), 0, poll_info, *count*sizeof(*poll_info)); + else + poll_info = HeapAlloc(GetProcessHeap(), 0, *count*sizeof(*poll_info)); + if (!poll_info) + { + ERR("couldn't allocate poll_info\n"); + LeaveCriticalSection(&protseq->cs); + return NULL; + } + + poll_info[0].fd = sockps->mgr_event_rcv; + poll_info[0].events = POLLIN; + *count = 1; + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) { + if (conn->sock != -1) + { + poll_info[*count].fd = conn->sock; + poll_info[*count].events = POLLIN; + (*count)++; + } + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + LeaveCriticalSection(&protseq->cs); + return poll_info; +} + +static void rpcrt4_protseq_sock_free_wait_array(RpcServerProtseq *protseq, void *array) +{ + HeapFree(GetProcessHeap(), 0, array); +} + +static int rpcrt4_protseq_sock_wait_for_new_connection(RpcServerProtseq *protseq, unsigned int count, void *wait_array) +{ + struct pollfd *poll_info = wait_array; + int ret, i; + RpcConnection *cconn; + RpcConnection_tcp *conn; + + if (!poll_info) + return -1; + + ret = poll(poll_info, count, -1); + if (ret < 0) + { + ERR("poll failed with error %d\n", ret); + return -1; + } + + for (i = 0; i < count; i++) + if (poll_info[i].revents & POLLIN) + { + /* RPC server event */ + if (i == 0) + { + char dummy; + read(poll_info[0].fd, &dummy, sizeof(dummy)); + return 0; + } + + /* find which connection got a RPC */ + EnterCriticalSection(&protseq->cs); + conn = CONTAINING_RECORD(protseq->conn, RpcConnection_tcp, common); + while (conn) { + if (poll_info[i].fd == conn->sock) break; + conn = CONTAINING_RECORD(conn->common.Next, RpcConnection_tcp, common); + } + cconn = NULL; + if (conn) + RPCRT4_SpawnConnection(&cconn, &conn->common); + else + ERR("failed to locate connection for fd %d\n", poll_info[i].fd); + LeaveCriticalSection(&protseq->cs); + if (cconn) + RPCRT4_new_client(cconn); + else + return -1; + } + + return 1; +} + +static const struct connection_ops conn_protseq_list[] = { + { "ncacn_np", + { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_SMB }, + rpcrt4_conn_np_alloc, + rpcrt4_ncacn_np_open, + rpcrt4_ncacn_np_handoff, + rpcrt4_conn_np_read, + rpcrt4_conn_np_write, + rpcrt4_conn_np_close, + rpcrt4_ncacn_np_get_top_of_tower, + rpcrt4_ncacn_np_parse_top_of_tower, + }, + { "ncalrpc", + { EPM_PROTOCOL_NCALRPC, EPM_PROTOCOL_PIPE }, + rpcrt4_conn_np_alloc, + rpcrt4_ncalrpc_open, + rpcrt4_ncalrpc_handoff, + rpcrt4_conn_np_read, + rpcrt4_conn_np_write, + rpcrt4_conn_np_close, + rpcrt4_ncalrpc_get_top_of_tower, + rpcrt4_ncalrpc_parse_top_of_tower, + }, + { "ncacn_ip_tcp", + { EPM_PROTOCOL_NCACN, EPM_PROTOCOL_TCP }, + rpcrt4_conn_tcp_alloc, + rpcrt4_ncacn_ip_tcp_open, + rpcrt4_conn_tcp_handoff, + rpcrt4_conn_tcp_read, + rpcrt4_conn_tcp_write, + rpcrt4_conn_tcp_close, + rpcrt4_ncacn_ip_tcp_get_top_of_tower, + rpcrt4_ncacn_ip_tcp_parse_top_of_tower, + } +}; + + +static const struct protseq_ops protseq_list[] = +{ + { + "ncacn_np", + rpcrt4_protseq_np_alloc, + rpcrt4_protseq_np_signal_state_changed, + rpcrt4_protseq_np_get_wait_array, + rpcrt4_protseq_np_free_wait_array, + rpcrt4_protseq_np_wait_for_new_connection, + rpcrt4_protseq_ncacn_np_open_endpoint, + }, + { + "ncalrpc", + rpcrt4_protseq_np_alloc, + rpcrt4_protseq_np_signal_state_changed, + rpcrt4_protseq_np_get_wait_array, + rpcrt4_protseq_np_free_wait_array, + rpcrt4_protseq_np_wait_for_new_connection, + rpcrt4_protseq_ncalrpc_open_endpoint, + }, + { + "ncacn_ip_tcp", + rpcrt4_protseq_sock_alloc, + rpcrt4_protseq_sock_signal_state_changed, + rpcrt4_protseq_sock_get_wait_array, + rpcrt4_protseq_sock_free_wait_array, + rpcrt4_protseq_sock_wait_for_new_connection, + rpcrt4_protseq_ncacn_ip_tcp_open_endpoint, + }, +}; + +#define ARRAYSIZE(a) (sizeof((a)) / sizeof((a)[0])) + +const struct protseq_ops *rpcrt4_get_protseq_ops(const char *protseq) +{ + int i; + for(i=0; iserver); + return Connection->ops->open_connection_client(Connection); +} + +RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection) +{ + TRACE("(Connection == ^%p)\n", Connection); + if (SecIsValidHandle(&Connection->ctx)) + { + DeleteSecurityContext(&Connection->ctx); + SecInvalidateHandle(&Connection->ctx); + } + rpcrt4_conn_close(Connection); + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, + LPCSTR Protseq, LPCSTR NetworkAddr, LPCSTR Endpoint, + LPCWSTR NetworkOptions, RpcAuthInfo* AuthInfo, RpcQualityOfService *QOS) +{ + const struct connection_ops *ops; + RpcConnection* NewConnection; + + ops = rpcrt4_get_conn_protseq_ops(Protseq); + if (!ops) + { + FIXME("not supported for protseq %s\n", Protseq); + return RPC_S_PROTSEQ_NOT_SUPPORTED; + } + + NewConnection = ops->alloc(); + NewConnection->Next = NULL; + NewConnection->server = server; + NewConnection->ops = ops; + NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + NewConnection->Endpoint = RPCRT4_strdupA(Endpoint); + NewConnection->NetworkOptions = RPCRT4_strdupW(NetworkOptions); + NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE; + memset(&NewConnection->ActiveInterface, 0, sizeof(NewConnection->ActiveInterface)); + NewConnection->NextCallId = 1; + + SecInvalidateHandle(&NewConnection->ctx); + memset(&NewConnection->exp, 0, sizeof(NewConnection->exp)); + NewConnection->attr = 0; + if (AuthInfo) RpcAuthInfo_AddRef(AuthInfo); + NewConnection->AuthInfo = AuthInfo; + NewConnection->encryption_auth_len = 0; + NewConnection->signature_auth_len = 0; + if (QOS) RpcQualityOfService_AddRef(QOS); + NewConnection->QOS = QOS; + + list_init(&NewConnection->conn_pool_entry); + + TRACE("connection: %p\n", NewConnection); + *Connection = NewConnection; + + return RPC_S_OK; +} + +RPC_STATUS RPCRT4_GetAssociation(LPCSTR Protseq, LPCSTR NetworkAddr, + LPCSTR Endpoint, LPCWSTR NetworkOptions, + RpcAssoc **assoc_out) +{ + RpcAssoc *assoc; + + EnterCriticalSection(&assoc_list_cs); + LIST_FOR_EACH_ENTRY(assoc, &assoc_list, RpcAssoc, entry) + { + if (!strcmp(Protseq, assoc->Protseq) && + !strcmp(NetworkAddr, assoc->NetworkAddr) && + !strcmp(Endpoint, assoc->Endpoint) && + ((!assoc->NetworkOptions && !NetworkOptions) || !strcmpW(NetworkOptions, assoc->NetworkOptions))) + { + assoc->refs++; + *assoc_out = assoc; + LeaveCriticalSection(&assoc_list_cs); + TRACE("using existing assoc %p\n", assoc); + return RPC_S_OK; + } + } + + assoc = HeapAlloc(GetProcessHeap(), 0, sizeof(*assoc)); + if (!assoc) + { + LeaveCriticalSection(&assoc_list_cs); + return RPC_S_OUT_OF_RESOURCES; + } + assoc->refs = 1; + list_init(&assoc->connection_pool); + InitializeCriticalSection(&assoc->cs); + assoc->Protseq = RPCRT4_strdupA(Protseq); + assoc->NetworkAddr = RPCRT4_strdupA(NetworkAddr); + assoc->Endpoint = RPCRT4_strdupA(Endpoint); + assoc->NetworkOptions = NetworkOptions ? RPCRT4_strdupW(NetworkOptions) : NULL; + assoc->assoc_group_id = 0; + list_add_head(&assoc_list, &assoc->entry); + *assoc_out = assoc; + + LeaveCriticalSection(&assoc_list_cs); + + TRACE("new assoc %p\n", assoc); + + return RPC_S_OK; +} + +ULONG RpcAssoc_Release(RpcAssoc *assoc) +{ + ULONG refs; + + EnterCriticalSection(&assoc_list_cs); + refs = --assoc->refs; + if (!refs) + list_remove(&assoc->entry); + LeaveCriticalSection(&assoc_list_cs); + + if (!refs) + { + RpcConnection *Connection, *cursor2; + + TRACE("destroying assoc %p\n", assoc); + + LIST_FOR_EACH_ENTRY_SAFE(Connection, cursor2, &assoc->connection_pool, RpcConnection, conn_pool_entry) + { + list_remove(&Connection->conn_pool_entry); + RPCRT4_DestroyConnection(Connection); + } + + HeapFree(GetProcessHeap(), 0, assoc->NetworkOptions); + HeapFree(GetProcessHeap(), 0, assoc->Endpoint); + HeapFree(GetProcessHeap(), 0, assoc->NetworkAddr); + HeapFree(GetProcessHeap(), 0, assoc->Protseq); + + HeapFree(GetProcessHeap(), 0, assoc); + } + + return refs; +} + +static RPC_STATUS RpcAssoc_BindConnection(RpcAssoc *assoc, RpcConnection *conn, + const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax) +{ + RpcPktHdr *hdr; + RpcPktHdr *response_hdr; + RPC_MESSAGE msg; + RPC_STATUS status; + + TRACE("sending bind request to server\n"); + + hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION, + RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, + assoc->assoc_group_id, + InterfaceId, TransferSyntax); + + status = RPCRT4_Send(conn, hdr, NULL, 0); + RPCRT4_FreeHeader(hdr); + if (status != RPC_S_OK) + return status; + + status = RPCRT4_Receive(conn, &response_hdr, &msg); + if (status != RPC_S_OK) + { + ERR("receive failed\n"); + return status; + } + + if (response_hdr->common.ptype != PKT_BIND_ACK) + { + ERR("failed to bind for interface %s, %d.%d\n", + debugstr_guid(&InterfaceId->SyntaxGUID), + InterfaceId->SyntaxVersion.MajorVersion, + InterfaceId->SyntaxVersion.MinorVersion); + RPCRT4_FreeHeader(response_hdr); + return RPC_S_PROTOCOL_ERROR; + } + + /* FIXME: do more checks? */ + + conn->assoc_group_id = response_hdr->bind_ack.assoc_gid; + conn->MaxTransmissionSize = response_hdr->bind_ack.max_tsize; + conn->ActiveInterface = *InterfaceId; + RPCRT4_FreeHeader(response_hdr); + return RPC_S_OK; +} + +static RpcConnection *RpcAssoc_GetIdleConnection(RpcAssoc *assoc, + const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax, const RpcAuthInfo *AuthInfo, + const RpcQualityOfService *QOS) +{ + RpcConnection *Connection; + EnterCriticalSection(&assoc->cs); + /* try to find a compatible connection from the connection pool */ + LIST_FOR_EACH_ENTRY(Connection, &assoc->connection_pool, RpcConnection, conn_pool_entry) + { + if (!memcmp(&Connection->ActiveInterface, InterfaceId, + sizeof(RPC_SYNTAX_IDENTIFIER)) && + RpcAuthInfo_IsEqual(Connection->AuthInfo, AuthInfo) && + RpcQualityOfService_IsEqual(Connection->QOS, QOS)) + { + list_remove(&Connection->conn_pool_entry); + LeaveCriticalSection(&assoc->cs); + TRACE("got connection from pool %p\n", Connection); + return Connection; + } + } + + LeaveCriticalSection(&assoc->cs); + return NULL; +} + +RPC_STATUS RpcAssoc_GetClientConnection(RpcAssoc *assoc, + const RPC_SYNTAX_IDENTIFIER *InterfaceId, + const RPC_SYNTAX_IDENTIFIER *TransferSyntax, RpcAuthInfo *AuthInfo, + RpcQualityOfService *QOS, RpcConnection **Connection) +{ + RpcConnection *NewConnection; + RPC_STATUS status; + + *Connection = RpcAssoc_GetIdleConnection(assoc, InterfaceId, TransferSyntax, AuthInfo, QOS); + if (*Connection) + return RPC_S_OK; + + /* create a new connection */ + status = RPCRT4_CreateConnection(&NewConnection, FALSE /* is this a server connection? */, + assoc->Protseq, assoc->NetworkAddr, + assoc->Endpoint, assoc->NetworkOptions, + AuthInfo, QOS); + if (status != RPC_S_OK) + return status; + + status = RPCRT4_OpenClientConnection(NewConnection); + if (status != RPC_S_OK) + { + RPCRT4_DestroyConnection(NewConnection); + return status; + } + + status = RpcAssoc_BindConnection(assoc, NewConnection, InterfaceId, TransferSyntax); + if (status != RPC_S_OK) + { + RPCRT4_DestroyConnection(NewConnection); + return status; + } + + *Connection = NewConnection; + + return RPC_S_OK; +} + +void RpcAssoc_ReleaseIdleConnection(RpcAssoc *assoc, RpcConnection *Connection) +{ + assert(!Connection->server); + EnterCriticalSection(&assoc->cs); + if (!assoc->assoc_group_id) assoc->assoc_group_id = Connection->assoc_group_id; + list_add_head(&assoc->connection_pool, &Connection->conn_pool_entry); + LeaveCriticalSection(&assoc->cs); +} + + +RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection) +{ + RPC_STATUS err; + + err = RPCRT4_CreateConnection(Connection, OldConnection->server, + rpcrt4_conn_get_name(OldConnection), + OldConnection->NetworkAddr, + OldConnection->Endpoint, NULL, + OldConnection->AuthInfo, OldConnection->QOS); + if (err == RPC_S_OK) + rpcrt4_conn_handoff(OldConnection, *Connection); + return err; +} + +RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection) +{ + TRACE("connection: %p\n", Connection); + + RPCRT4_CloseConnection(Connection); + RPCRT4_strfree(Connection->Endpoint); + RPCRT4_strfree(Connection->NetworkAddr); + HeapFree(GetProcessHeap(), 0, Connection->NetworkOptions); + if (Connection->AuthInfo) RpcAuthInfo_Release(Connection->AuthInfo); + if (Connection->QOS) RpcQualityOfService_Release(Connection->QOS); + HeapFree(GetProcessHeap(), 0, Connection); + return RPC_S_OK; +} + +RPC_STATUS RpcTransport_GetTopOfTower(unsigned char *tower_data, + size_t *tower_size, + const char *protseq, + const char *networkaddr, + const char *endpoint) +{ + twr_empty_floor_t *protocol_floor; + const struct connection_ops *protseq_ops = rpcrt4_get_conn_protseq_ops(protseq); + + *tower_size = 0; + + if (!protseq_ops) + return RPC_S_INVALID_RPC_PROTSEQ; + + if (!tower_data) + { + *tower_size = sizeof(*protocol_floor); + *tower_size += protseq_ops->get_top_of_tower(NULL, networkaddr, endpoint); + return RPC_S_OK; + } + + protocol_floor = (twr_empty_floor_t *)tower_data; + protocol_floor->count_lhs = sizeof(protocol_floor->protid); + protocol_floor->protid = protseq_ops->epm_protocols[0]; + protocol_floor->count_rhs = 0; + + tower_data += sizeof(*protocol_floor); + + *tower_size = protseq_ops->get_top_of_tower(tower_data, networkaddr, endpoint); + if (!*tower_size) + return EPT_S_NOT_REGISTERED; + + *tower_size += sizeof(*protocol_floor); + + return RPC_S_OK; +} + +RPC_STATUS RpcTransport_ParseTopOfTower(const unsigned char *tower_data, + size_t tower_size, + char **protseq, + char **networkaddr, + char **endpoint) +{ + const twr_empty_floor_t *protocol_floor; + const twr_empty_floor_t *floor4; + const struct connection_ops *protseq_ops = NULL; + RPC_STATUS status; + int i; + + if (tower_size < sizeof(*protocol_floor)) + return EPT_S_NOT_REGISTERED; + + protocol_floor = (const twr_empty_floor_t *)tower_data; + tower_data += sizeof(*protocol_floor); + tower_size -= sizeof(*protocol_floor); + if ((protocol_floor->count_lhs != sizeof(protocol_floor->protid)) || + (protocol_floor->count_rhs > tower_size)) + return EPT_S_NOT_REGISTERED; + tower_data += protocol_floor->count_rhs; + tower_size -= protocol_floor->count_rhs; + + floor4 = (const twr_empty_floor_t *)tower_data; + if ((tower_size < sizeof(*floor4)) || + (floor4->count_lhs != sizeof(floor4->protid))) + return EPT_S_NOT_REGISTERED; + + for(i = 0; i < ARRAYSIZE(conn_protseq_list); i++) + if ((protocol_floor->protid == conn_protseq_list[i].epm_protocols[0]) && + (floor4->protid == conn_protseq_list[i].epm_protocols[1])) + { + protseq_ops = &conn_protseq_list[i]; + break; + } + + if (!protseq_ops) + return EPT_S_NOT_REGISTERED; + + status = protseq_ops->parse_top_of_tower(tower_data, tower_size, networkaddr, endpoint); + + if ((status == RPC_S_OK) && protseq) + { + *protseq = I_RpcAllocate(strlen(protseq_ops->name) + 1); + strcpy(*protseq, protseq_ops->name); + } + + return status; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidW (RPCRT4.@) + * + * Checks if the given protocol sequence is known by the RPC system. + * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED. + * + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(RPC_WSTR protseq) +{ + char ps[0x10]; + + WideCharToMultiByte(CP_ACP, 0, protseq, -1, + ps, sizeof ps, NULL, NULL); + if (rpcrt4_get_conn_protseq_ops(ps)) + return RPC_S_OK; + + FIXME("Unknown protseq %s\n", debugstr_w(protseq)); + + return RPC_S_INVALID_RPC_PROTSEQ; +} + +/*********************************************************************** + * RpcNetworkIsProtseqValidA (RPCRT4.@) + */ +RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(RPC_CSTR protseq) +{ + UNICODE_STRING protseqW; + + if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq)) + { + RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer); + RtlFreeUnicodeString(&protseqW); + return ret; + } + return RPC_S_OUT_OF_MEMORY; +} diff --git a/reactos/dll/win32/rpcrt4_new/rpcrt4.rbuild b/reactos/dll/win32/rpcrt4_new/rpcrt4.rbuild new file mode 100644 index 00000000000..1e4e1c09dc3 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpcrt4.rbuild @@ -0,0 +1,41 @@ + + + + . + include/reactos/wine + + + 0x600 + 0x501 + 0x501 + + + + + wine + uuid + ntdll + kernel32 + advapi32 + secur32 + iphlpapi + ws2_32 + cproxy.c + cpsf.c + cstub.c + ndr_clientserver.c + ndr_fullpointer.c + ndr_marshall.c + ndr_ole.c + ndr_stubless.c + rpc_binding.c + rpc_epmap.c + rpc_message.c + rpc_server.c + rpc_transport.c + rpcrt4_main.c + rpcss_np_client.c + unix_func.c + rpcrt4.rc + rpcrt4.spec + diff --git a/reactos/dll/win32/rpcrt4_new/rpcrt4.rc b/reactos/dll/win32/rpcrt4_new/rpcrt4.rc new file mode 100644 index 00000000000..8b8603e92dd --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpcrt4.rc @@ -0,0 +1,7 @@ +#include + +#define REACTOS_VERSION_DLL +#define REACTOS_STR_FILE_DESCRIPTION "ReactOS RPC server API\0" +#define REACTOS_STR_INTERNAL_NAME "rpcrt4\0" +#define REACTOS_STR_ORIGINAL_FILENAME "rpcrt4.dll\0" +#include diff --git a/reactos/dll/win32/rpcrt4_new/rpcrt4.spec b/reactos/dll/win32/rpcrt4_new/rpcrt4.spec new file mode 100644 index 00000000000..c5498d7037a --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpcrt4.spec @@ -0,0 +1,565 @@ +@ stdcall CreateProxyFromTypeInfo(ptr ptr ptr ptr ptr) +@ stub CreateStubFromTypeInfo +@ stdcall CStdStubBuffer_AddRef(ptr) +@ stdcall CStdStubBuffer_Connect(ptr ptr) +@ stdcall CStdStubBuffer_CountRefs(ptr) +@ stdcall CStdStubBuffer_DebugServerQueryInterface(ptr ptr) +@ stdcall CStdStubBuffer_DebugServerRelease(ptr ptr) +@ stdcall CStdStubBuffer_Disconnect(ptr) +@ stdcall CStdStubBuffer_Invoke(ptr ptr ptr) +@ stdcall CStdStubBuffer_IsIIDSupported(ptr ptr) +@ stdcall CStdStubBuffer_QueryInterface(ptr ptr ptr) +@ stub CreateServerInterfaceFromStub # wxp +@ stdcall DceErrorInqTextA (long ptr) +@ stdcall DceErrorInqTextW (long ptr) +@ stdcall -private DllRegisterServer() +@ stub GlobalMutexClearExternal +@ stub GlobalMutexRequestExternal +@ stdcall IUnknown_AddRef_Proxy(ptr) +@ stdcall IUnknown_QueryInterface_Proxy(ptr ptr ptr) +@ stdcall IUnknown_Release_Proxy(ptr) +@ stub I_RpcAbortAsyncCall +@ stdcall I_RpcAllocate(long) +@ stub I_RpcAsyncAbortCall +@ stub I_RpcAsyncSendReceive # NT4 +@ stub I_RpcAsyncSetHandle +@ stub I_RpcBCacheAllocate +@ stub I_RpcBCacheFree +@ stub I_RpcBindingCopy +@ stub I_RpcBindingInqConnId +@ stub I_RpcBindingInqDynamicEndPoint +@ stub I_RpcBindingInqDynamicEndPointA +@ stub I_RpcBindingInqDynamicEndPointW +@ stub I_RpcBindingInqLocalClientPID # wxp +@ stub I_RpcBindingInqSecurityContext +@ stub I_RpcBindingInqTransportType +@ stub I_RpcBindingInqWireIdForSnego +@ stub I_RpcBindingIsClientLocal +# 9x version of I_RpcBindingSetAsync has 3 arguments, not 2 +@ stdcall I_RpcBindingSetAsync(ptr ptr) +@ stub I_RpcBindingToStaticStringBindingW +@ stub I_RpcClearMutex +@ stub I_RpcConnectionInqSockBuffSize2 +@ stub I_RpcConnectionInqSockBuffSize +@ stub I_RpcConnectionSetSockBuffSize +@ stub I_RpcDeleteMutex +@ stub I_RpcEnableWmiTrace # wxp +@ stub I_RpcExceptionFilter # wxp +@ stdcall I_RpcFree(ptr) +@ stdcall I_RpcFreeBuffer(ptr) +@ stub I_RpcFreePipeBuffer +@ stub I_RpcGetAssociationContext +@ stdcall I_RpcGetBuffer(ptr) +@ stub I_RpcGetBufferWithObject +@ stub I_RpcGetCurrentCallHandle +@ stub I_RpcGetExtendedError +@ stub I_RpcGetServerContextList +@ stub I_RpcGetThreadEvent # win9x +@ stub I_RpcGetThreadWindowHandle # win9x +@ stub I_RpcIfInqTransferSyntaxes +@ stub I_RpcLaunchDatagramReceiveThread # win9x +@ stub I_RpcLogEvent +@ stdcall I_RpcMapWin32Status(long) +@ stub I_RpcMonitorAssociation +@ stub I_RpcNegotiateTransferSyntax # wxp +@ stub I_RpcNsBindingSetEntryName +@ stub I_RpcNsBindingSetEntryNameA +@ stub I_RpcNsBindingSetEntryNameW +@ stub I_RpcNsInterfaceExported +@ stub I_RpcNsInterfaceUnexported +@ stub I_RpcParseSecurity +@ stub I_RpcPauseExecution +@ stub I_RpcProxyNewConnection # wxp +@ stub I_RpcReallocPipeBuffer +@ stdcall I_RpcReceive(ptr) +@ stub I_RpcRequestMutex +@ stdcall I_RpcSend(ptr) +@ stdcall I_RpcSendReceive(ptr) +@ stub I_RpcServerAllocateIpPort +@ stub I_RpcServerInqAddressChangeFn +@ stub I_RpcServerInqLocalConnAddress # wxp +@ stub I_RpcServerInqTransportType +@ stub I_RpcServerRegisterForwardFunction +@ stub I_RpcServerSetAddressChangeFn +@ stdcall I_RpcServerStartListening(ptr) # win9x +@ stdcall I_RpcServerStopListening() # win9x +@ stub I_RpcServerUnregisterEndpointA # win9x +@ stub I_RpcServerUnregisterEndpointW # win9x +@ stub I_RpcServerUseProtseq2A +@ stub I_RpcServerUseProtseq2W +@ stub I_RpcServerUseProtseqEp2A +@ stub I_RpcServerUseProtseqEp2W +@ stub I_RpcSetAssociationContext # win9x +@ stub I_RpcSetAsyncHandle +@ stub I_RpcSetServerContextList +@ stub I_RpcSetThreadParams # win9x +@ stub I_RpcSetWMsgEndpoint # NT4 +@ stub I_RpcSsDontSerializeContext +@ stub I_RpcStopMonitorAssociation +@ stub I_RpcSystemFunction001 # wxp (oh, brother!) +@ stub I_RpcTransCancelMigration # win9x +@ stub I_RpcTransClientMaxFrag # win9x +@ stub I_RpcTransClientReallocBuffer # win9x +@ stub I_RpcTransConnectionAllocatePacket +@ stub I_RpcTransConnectionFreePacket +@ stub I_RpcTransConnectionReallocPacket +@ stub I_RpcTransDatagramAllocate2 +@ stub I_RpcTransDatagramAllocate +@ stub I_RpcTransDatagramFree +@ stub I_RpcTransGetAddressList +@ stub I_RpcTransGetThreadEvent +@ stub I_RpcTransIoCancelled +@ stub I_RpcTransMaybeMakeReceiveAny # win9x +@ stub I_RpcTransMaybeMakeReceiveDirect # win9x +@ stub I_RpcTransPingServer # win9x +@ stub I_RpcTransServerFindConnection # win9x +@ stub I_RpcTransServerFreeBuffer # win9x +@ stub I_RpcTransServerMaxFrag # win9x +@ stub I_RpcTransServerNewConnection +@ stub I_RpcTransServerProtectThread # win9x +@ stub I_RpcTransServerReallocBuffer # win9x +@ stub I_RpcTransServerReceiveDirectReady # win9x +@ stub I_RpcTransServerUnprotectThread # win9x +@ stub I_RpcTurnOnEEInfoPropagation # wxp +@ stdcall I_RpcWindowProc(ptr long long long) # win9x +@ stub I_RpcltDebugSetPDUFilter +@ stub I_UuidCreate +@ stub MIDL_wchar_strcpy +@ stub MIDL_wchar_strlen +@ stub MesBufferHandleReset +@ stub MesDecodeBufferHandleCreate +@ stub MesDecodeIncrementalHandleCreate +@ stub MesEncodeDynBufferHandleCreate +@ stub MesEncodeFixedBufferHandleCreate +@ stub MesEncodeIncrementalHandleCreate +@ stub MesHandleFree +@ stub MesIncrementalHandleReset +@ stub MesInqProcEncodingId +@ stub MqGetContext # win9x +@ stub MqRegisterQueue # win9x +@ stdcall NDRCContextBinding(ptr) +@ stdcall NDRCContextMarshall(ptr ptr) +@ stdcall NDRCContextUnmarshall(ptr ptr ptr long) +@ stdcall NDRSContextMarshall2(ptr ptr ptr ptr ptr long) +@ stdcall NDRSContextMarshall(ptr ptr ptr) +@ stdcall NDRSContextMarshallEx(ptr ptr ptr ptr) +@ stdcall NDRSContextUnmarshall2(ptr ptr ptr ptr long) +@ stdcall NDRSContextUnmarshall(ptr ptr) +@ stdcall NDRSContextUnmarshallEx(ptr ptr ptr) +@ stub NDRcopy +@ stdcall NdrAllocate(ptr long) +@ stub NdrAsyncClientCall +@ stub NdrAsyncServerCall +@ stdcall NdrByteCountPointerBufferSize(ptr ptr ptr) +@ stdcall NdrByteCountPointerFree(ptr ptr ptr) +@ stdcall NdrByteCountPointerMarshall(ptr ptr ptr) +@ stdcall NdrByteCountPointerUnmarshall(ptr ptr ptr long) +@ stdcall NdrCStdStubBuffer2_Release(ptr ptr) +@ stdcall NdrCStdStubBuffer_Release(ptr ptr) +@ stdcall NdrClearOutParameters(ptr ptr ptr) +@ varargs NdrClientCall2(ptr ptr) +@ varargs NdrClientCall(ptr ptr) NdrClientCall2 +@ stdcall NdrClientContextMarshall(ptr ptr long) +@ stdcall NdrClientContextUnmarshall(ptr ptr ptr) +@ stub NdrClientInitialize +@ stdcall NdrClientInitializeNew(ptr ptr ptr long) +@ stdcall NdrComplexArrayBufferSize(ptr ptr ptr) +@ stdcall NdrComplexArrayFree(ptr ptr ptr) +@ stdcall NdrComplexArrayMarshall(ptr ptr ptr) +@ stdcall NdrComplexArrayMemorySize(ptr ptr) +@ stdcall NdrComplexArrayUnmarshall(ptr ptr ptr long) +@ stdcall NdrComplexStructBufferSize(ptr ptr ptr) +@ stdcall NdrComplexStructFree(ptr ptr ptr) +@ stdcall NdrComplexStructMarshall(ptr ptr ptr) +@ stdcall NdrComplexStructMemorySize(ptr ptr) +@ stdcall NdrComplexStructUnmarshall(ptr ptr ptr long) +@ stdcall NdrConformantArrayBufferSize(ptr ptr ptr) +@ stdcall NdrConformantArrayFree(ptr ptr ptr) +@ stdcall NdrConformantArrayMarshall(ptr ptr ptr) +@ stdcall NdrConformantArrayMemorySize(ptr ptr) +@ stdcall NdrConformantArrayUnmarshall(ptr ptr ptr long) +@ stdcall NdrConformantStringBufferSize(ptr ptr ptr) +@ stdcall NdrConformantStringMarshall(ptr ptr ptr) +@ stdcall NdrConformantStringMemorySize(ptr ptr) +@ stdcall NdrConformantStringUnmarshall(ptr ptr ptr long) +@ stdcall NdrConformantStructBufferSize(ptr ptr ptr) +@ stdcall NdrConformantStructFree(ptr ptr ptr) +@ stdcall NdrConformantStructMarshall(ptr ptr ptr) +@ stdcall NdrConformantStructMemorySize(ptr ptr) +@ stdcall NdrConformantStructUnmarshall(ptr ptr ptr long) +@ stdcall NdrConformantVaryingArrayBufferSize(ptr ptr ptr) +@ stdcall NdrConformantVaryingArrayFree(ptr ptr ptr) +@ stdcall NdrConformantVaryingArrayMarshall(ptr ptr ptr) +@ stdcall NdrConformantVaryingArrayMemorySize(ptr ptr) +@ stdcall NdrConformantVaryingArrayUnmarshall(ptr ptr ptr long) +@ stdcall NdrConformantVaryingStructBufferSize(ptr ptr ptr) +@ stdcall NdrConformantVaryingStructFree(ptr ptr ptr) +@ stdcall NdrConformantVaryingStructMarshall(ptr ptr ptr) +@ stdcall NdrConformantVaryingStructMemorySize(ptr ptr) +@ stdcall NdrConformantVaryingStructUnmarshall(ptr ptr ptr long) +@ stdcall NdrContextHandleInitialize(ptr ptr) +@ stdcall NdrContextHandleSize(ptr ptr ptr) +@ stdcall NdrConvert2(ptr ptr long) +@ stdcall NdrConvert(ptr ptr) +@ stub NdrCorrelationFree +@ stub NdrCorrelationInitialize +@ stub NdrCorrelationPass +@ stub NdrDcomAsyncClientCall +@ stub NdrDcomAsyncStubCall +@ stdcall NdrDllCanUnloadNow(ptr) +@ stdcall NdrDllGetClassObject(ptr ptr ptr ptr ptr ptr) +@ stdcall NdrDllRegisterProxy(long ptr ptr) +@ stdcall NdrDllUnregisterProxy(long ptr ptr) +@ stdcall NdrEncapsulatedUnionBufferSize(ptr ptr ptr) +@ stdcall NdrEncapsulatedUnionFree(ptr ptr ptr) +@ stdcall NdrEncapsulatedUnionMarshall(ptr ptr ptr) +@ stdcall NdrEncapsulatedUnionMemorySize(ptr ptr) +@ stdcall NdrEncapsulatedUnionUnmarshall(ptr ptr ptr long) +@ stdcall NdrFixedArrayBufferSize(ptr ptr ptr) +@ stdcall NdrFixedArrayFree(ptr ptr ptr) +@ stdcall NdrFixedArrayMarshall(ptr ptr ptr) +@ stdcall NdrFixedArrayMemorySize(ptr ptr) +@ stdcall NdrFixedArrayUnmarshall(ptr ptr ptr long) +@ stdcall NdrFreeBuffer(ptr) +@ stdcall NdrFullPointerFree(ptr ptr) +@ stdcall NdrFullPointerInsertRefId(ptr long ptr) +@ stdcall NdrFullPointerQueryPointer(ptr ptr long ptr) +@ stdcall NdrFullPointerQueryRefId(ptr long long ptr) +@ stdcall NdrFullPointerXlatFree(ptr) +@ stdcall NdrFullPointerXlatInit(long long) +@ stdcall NdrGetBuffer(ptr long ptr) +@ stub NdrGetDcomProtocolVersion +@ stub NdrGetPartialBuffer +@ stub NdrGetPipeBuffer +@ stub NdrGetSimpleTypeBufferAlignment # wxp +@ stub NdrGetSimpleTypeBufferSize # wxp +@ stub NdrGetSimpleTypeMemorySize # wxp +@ stub NdrGetTypeFlags # wxp +@ stub NdrGetUserMarshallInfo +@ stub NdrHardStructBufferSize #(ptr ptr ptr) +@ stub NdrHardStructFree #(ptr ptr ptr) +@ stub NdrHardStructMarshall #(ptr ptr ptr) +@ stub NdrHardStructMemorySize #(ptr ptr) +@ stub NdrHardStructUnmarshall #(ptr ptr ptr long) +@ stdcall NdrInterfacePointerBufferSize(ptr ptr ptr) +@ stdcall NdrInterfacePointerFree(ptr ptr ptr) +@ stdcall NdrInterfacePointerMarshall(ptr ptr ptr) +@ stdcall NdrInterfacePointerMemorySize(ptr ptr) +@ stdcall NdrInterfacePointerUnmarshall(ptr ptr ptr long) +@ stub NdrIsAppDoneWithPipes +@ stdcall NdrMapCommAndFaultStatus(ptr ptr ptr long) +@ stub NdrMarkNextActivePipe +@ stub NdrMesProcEncodeDecode2 +@ stub NdrMesProcEncodeDecode +@ stub NdrMesSimpleTypeAlignSize +@ stub NdrMesSimpleTypeDecode +@ stub NdrMesSimpleTypeEncode +@ stub NdrMesTypeAlignSize2 +@ stub NdrMesTypeAlignSize +@ stub NdrMesTypeDecode2 +@ stub NdrMesTypeDecode +@ stub NdrMesTypeEncode2 +@ stub NdrMesTypeEncode +@ stub NdrMesTypeFree2 +@ stdcall NdrNonConformantStringBufferSize(ptr ptr ptr) +@ stdcall NdrNonConformantStringMarshall(ptr ptr ptr) +@ stdcall NdrNonConformantStringMemorySize(ptr ptr) +@ stdcall NdrNonConformantStringUnmarshall(ptr ptr ptr long) +@ stdcall NdrNonEncapsulatedUnionBufferSize(ptr ptr ptr) +@ stdcall NdrNonEncapsulatedUnionFree(ptr ptr ptr) +@ stdcall NdrNonEncapsulatedUnionMarshall(ptr ptr ptr) +@ stdcall NdrNonEncapsulatedUnionMemorySize(ptr ptr) +@ stdcall NdrNonEncapsulatedUnionUnmarshall(ptr ptr ptr long) +@ stub NdrNsGetBuffer +@ stub NdrNsSendReceive +@ stdcall NdrOleAllocate(long) +@ stdcall NdrOleFree(ptr) +@ stub NdrOutInit # wxp +@ stub NdrPartialIgnoreClientBufferSize # wxp +@ stub NdrPartialIgnoreClientMarshall # wxp +@ stub NdrPartialIgnoreServerInitialize # wxp +@ stub NdrPartialIgnoreServerUnmarshall # wxp +@ stub NdrPipePull +@ stub NdrPipePush +@ stub NdrPipeSendReceive +@ stub NdrPipesDone +@ stub NdrPipesInitialize +@ stdcall NdrPointerBufferSize(ptr ptr ptr) +@ stdcall NdrPointerFree(ptr ptr ptr) +@ stdcall NdrPointerMarshall(ptr ptr ptr) +@ stdcall NdrPointerMemorySize(ptr ptr) +@ stdcall NdrPointerUnmarshall(ptr ptr ptr long) +@ stdcall NdrProxyErrorHandler(long) +@ stdcall NdrProxyFreeBuffer(ptr ptr) +@ stdcall NdrProxyGetBuffer(ptr ptr) +@ stdcall NdrProxyInitialize(ptr ptr ptr ptr long) +@ stdcall NdrProxySendReceive(ptr ptr) +@ stub NdrRangeUnmarshall +@ stub NdrRpcSmClientAllocate +@ stub NdrRpcSmClientFree +@ stub NdrRpcSmSetClientToOsf +@ stub NdrRpcSsDefaultAllocate +@ stub NdrRpcSsDefaultFree +@ stub NdrRpcSsDisableAllocate +@ stub NdrRpcSsEnableAllocate +@ stdcall NdrSendReceive(ptr ptr) +@ stdcall NdrServerCall2(ptr) +@ stub NdrServerCall +@ stdcall NdrServerContextMarshall(ptr ptr long) +@ stdcall NdrServerContextNewMarshall(ptr ptr ptr ptr) # wxp +@ stdcall NdrServerContextNewUnmarshall(ptr ptr) # wxp +@ stdcall NdrServerContextUnmarshall(ptr) +@ stub NdrServerInitialize +@ stub NdrServerInitializeMarshall +@ stdcall NdrServerInitializeNew(ptr ptr ptr) +@ stub NdrServerInitializePartial # wxp +@ stub NdrServerInitializeUnmarshall +@ stub NdrServerMarshall +@ stub NdrServerUnmarshall +@ stdcall NdrSimpleStructBufferSize(ptr ptr ptr) +@ stdcall NdrSimpleStructFree(ptr ptr ptr) +@ stdcall NdrSimpleStructMarshall(ptr ptr ptr) +@ stdcall NdrSimpleStructMemorySize(ptr ptr) +@ stdcall NdrSimpleStructUnmarshall(ptr ptr ptr long) +@ stdcall NdrSimpleTypeMarshall(ptr ptr long) +@ stdcall NdrSimpleTypeUnmarshall(ptr ptr long) +@ stdcall NdrStubCall2(ptr ptr ptr ptr) +@ stub NdrStubCall +@ stdcall NdrStubForwardingFunction(ptr ptr ptr ptr) +@ stdcall NdrStubGetBuffer(ptr ptr ptr) +@ stdcall NdrStubInitialize(ptr ptr ptr ptr) +@ stub NdrStubInitializeMarshall +@ stub NdrTypeFlags # wxp +@ stub NdrTypeFree # wxp +@ stub NdrTypeMarshall # wxp +@ stub NdrTypeSize # wxp +@ stub NdrTypeUnmarshall # wxp +@ stub NdrUnmarshallBasetypeInline # wxp +@ stdcall NdrUserMarshalBufferSize(ptr ptr ptr) +@ stdcall NdrUserMarshalFree(ptr ptr ptr) +@ stdcall NdrUserMarshalMarshall(ptr ptr ptr) +@ stdcall NdrUserMarshalMemorySize(ptr ptr) +@ stub NdrUserMarshalSimpleTypeConvert +@ stdcall NdrUserMarshalUnmarshall(ptr ptr ptr long) +@ stdcall NdrVaryingArrayBufferSize(ptr ptr ptr) +@ stdcall NdrVaryingArrayFree(ptr ptr ptr) +@ stdcall NdrVaryingArrayMarshall(ptr ptr ptr) +@ stdcall NdrVaryingArrayMemorySize(ptr ptr) +@ stdcall NdrVaryingArrayUnmarshall(ptr ptr ptr long) +@ stdcall NdrXmitOrRepAsBufferSize(ptr ptr ptr) +@ stdcall NdrXmitOrRepAsFree(ptr ptr ptr) +@ stdcall NdrXmitOrRepAsMarshall(ptr ptr ptr) +@ stdcall NdrXmitOrRepAsMemorySize(ptr ptr) +@ stdcall NdrXmitOrRepAsUnmarshall(ptr ptr ptr long) +@ stub NdrpCreateProxy # wxp +@ stub NdrpCreateStub # wxp +@ stub NdrpGetProcFormatString # wxp +@ stub NdrpGetTypeFormatString # wxp +@ stub NdrpGetTypeGenCookie # wxp +@ stub NdrpMemoryIncrement # wxp +@ stub NdrpReleaseTypeFormatString # wxp +@ stub NdrpReleaseTypeGenCookie # wxp +@ stub NdrpSetRpcSsDefaults +@ stub NdrpVarVtOfTypeDesc # wxp +@ stub PerformRpcInitialization +@ stub RpcAbortAsyncCall +@ stub RpcAsyncAbortCall +@ stub RpcAsyncCancelCall +@ stub RpcAsyncCompleteCall +@ stub RpcAsyncGetCallStatus +@ stub RpcAsyncInitializeHandle +@ stub RpcAsyncRegisterInfo +@ stdcall RpcBindingCopy(ptr ptr) +@ stdcall RpcBindingFree(ptr) +@ stdcall RpcBindingFromStringBindingA(str ptr) +@ stdcall RpcBindingFromStringBindingW(wstr ptr) +@ stub RpcBindingInqAuthClientA +@ stub RpcBindingInqAuthClientExA +@ stub RpcBindingInqAuthClientExW +@ stub RpcBindingInqAuthClientW +@ stdcall RpcBindingInqAuthInfoA(ptr ptr ptr ptr ptr ptr) +@ stdcall RpcBindingInqAuthInfoExA(ptr ptr ptr ptr ptr ptr long ptr) +@ stdcall RpcBindingInqAuthInfoExW(ptr ptr ptr ptr ptr ptr long ptr) +@ stdcall RpcBindingInqAuthInfoW(ptr ptr ptr ptr ptr ptr) +@ stdcall RpcBindingInqObject(ptr ptr) +@ stub RpcBindingInqOption +@ stub RpcBindingReset +@ stub RpcBindingServerFromClient +@ stdcall RpcBindingSetAuthInfoA(ptr str long long ptr long) +@ stdcall RpcBindingSetAuthInfoExA(ptr str long long ptr long ptr) +@ stdcall RpcBindingSetAuthInfoExW(ptr wstr long long ptr long ptr) +@ stdcall RpcBindingSetAuthInfoW(ptr wstr long long ptr long) +@ stdcall RpcBindingSetObject(ptr ptr) +@ stdcall RpcBindingSetOption(ptr long long) +@ stdcall RpcBindingToStringBindingA(ptr ptr) +@ stdcall RpcBindingToStringBindingW(ptr ptr) +@ stdcall RpcBindingVectorFree(ptr) +@ stub RpcCancelAsyncCall +@ stub RpcCancelThread +@ stub RpcCancelThreadEx +@ stub RpcCertGeneratePrincipalNameA +@ stub RpcCertGeneratePrincipalNameW +@ stub RpcCompleteAsyncCall +@ stdcall RpcEpRegisterA(ptr ptr ptr str) +@ stub RpcEpRegisterNoReplaceA +@ stub RpcEpRegisterNoReplaceW +@ stub RpcEpRegisterW +@ stdcall RpcEpResolveBinding(ptr ptr) +@ stdcall RpcEpUnregister(ptr ptr ptr) +@ stub RpcErrorAddRecord # wxp +@ stub RpcErrorClearInformation # wxp +@ stub RpcErrorEndEnumeration # wxp +@ stub RpcErrorGetNextRecord # wxp +@ stub RpcErrorLoadErrorInfo # wxp +@ stub RpcErrorNumberOfRecords # wxp +@ stub RpcErrorResetEnumeration # wxp +@ stub RpcErrorSaveErrorInfo # wxp +@ stub RpcErrorStartEnumeration # wxp +@ stub RpcFreeAuthorizationContext # wxp +@ stub RpcGetAsyncCallStatus +@ stub RpcIfIdVectorFree +@ stub RpcIfInqId +@ stdcall RpcImpersonateClient(ptr) +@ stub RpcInitializeAsyncHandle +@ stub RpcMgmtBindingInqParameter # win9x +@ stub RpcMgmtBindingSetParameter # win9x +@ stdcall RpcMgmtEnableIdleCleanup() +@ stdcall RpcMgmtEpEltInqBegin(ptr long ptr long ptr ptr) +@ stub RpcMgmtEpEltInqDone +@ stub RpcMgmtEpEltInqNextA +@ stub RpcMgmtEpEltInqNextW +@ stub RpcMgmtEpUnregister +@ stub RpcMgmtInqComTimeout +@ stub RpcMgmtInqDefaultProtectLevel +@ stdcall RpcMgmtInqIfIds(ptr ptr) +@ stub RpcMgmtInqParameter # win9x +@ stub RpcMgmtInqServerPrincNameA +@ stub RpcMgmtInqServerPrincNameW +@ stub RpcMgmtInqStats +@ stdcall RpcMgmtIsServerListening(ptr) +@ stub RpcMgmtSetAuthorizationFn +@ stub RpcMgmtSetCancelTimeout +@ stdcall RpcMgmtSetComTimeout(ptr long) +@ stub RpcMgmtSetParameter # win9x +@ stdcall RpcMgmtSetServerStackSize(long) +@ stub RpcMgmtStatsVectorFree +@ stdcall RpcMgmtStopServerListening(ptr) +@ stdcall RpcMgmtWaitServerListen() +@ stub RpcNetworkInqProtseqsA +@ stub RpcNetworkInqProtseqsW +@ stdcall RpcNetworkIsProtseqValidA(ptr) +@ stdcall RpcNetworkIsProtseqValidW(ptr) +@ stub RpcNsBindingInqEntryNameA +@ stub RpcNsBindingInqEntryNameW +@ stub RpcObjectInqType +@ stub RpcObjectSetInqFn +@ stdcall RpcObjectSetType(ptr ptr) +@ stub RpcProtseqVectorFreeA +@ stub RpcProtseqVectorFreeW +@ stdcall RpcRaiseException(long) +@ stub RpcRegisterAsyncInfo +@ stdcall RpcRevertToSelf() +@ stdcall RpcRevertToSelfEx(ptr) +@ stdcall RpcServerInqBindings(ptr) +@ stub RpcServerInqCallAttributesA # wxp +@ stub RpcServerInqCallAttributesW # wxp +@ stub RpcServerInqDefaultPrincNameA +@ stub RpcServerInqDefaultPrincNameW +@ stub RpcServerInqIf +@ stdcall RpcServerListen(long long long) +@ stdcall RpcServerRegisterAuthInfoA(str long ptr ptr) +@ stdcall RpcServerRegisterAuthInfoW(wstr long ptr ptr) +@ stdcall RpcServerRegisterIf2(ptr ptr ptr long long long ptr) +@ stdcall RpcServerRegisterIf(ptr ptr ptr) +@ stdcall RpcServerRegisterIfEx(ptr ptr ptr long long ptr) +@ stub RpcServerTestCancel +@ stdcall RpcServerUnregisterIf(ptr ptr long) +@ stdcall RpcServerUnregisterIfEx(ptr ptr long) +@ stub RpcServerUseAllProtseqs +@ stub RpcServerUseAllProtseqsEx +@ stub RpcServerUseAllProtseqsIf +@ stub RpcServerUseAllProtseqsIfEx +@ stdcall RpcServerUseProtseqA(str long ptr) +@ stdcall RpcServerUseProtseqEpA(str long str ptr) +@ stdcall RpcServerUseProtseqEpExA(str long str ptr ptr) +@ stdcall RpcServerUseProtseqEpExW(wstr long wstr ptr ptr) +@ stdcall RpcServerUseProtseqEpW(wstr long wstr ptr) +@ stub RpcServerUseProtseqExA +@ stub RpcServerUseProtseqExW +@ stub RpcServerUseProtseqIfA +@ stub RpcServerUseProtseqIfExA +@ stub RpcServerUseProtseqIfExW +@ stub RpcServerUseProtseqIfW +@ stdcall RpcServerUseProtseqW(wstr long ptr) +@ stub RpcServerYield +@ stub RpcSmAllocate +@ stub RpcSmClientFree +@ stub RpcSmDestroyClientContext +@ stub RpcSmDisableAllocate +@ stub RpcSmEnableAllocate +@ stub RpcSmFree +@ stub RpcSmGetThreadHandle +@ stub RpcSmSetClientAllocFree +@ stub RpcSmSetThreadHandle +@ stub RpcSmSwapClientAllocFree +@ stub RpcSsAllocate +@ stub RpcSsContextLockExclusive # wxp +@ stub RpcSsContextLockShared # wxp +@ stub RpcSsDestroyClientContext +@ stub RpcSsDisableAllocate +@ stub RpcSsDontSerializeContext +@ stub RpcSsEnableAllocate +@ stub RpcSsFree +@ stub RpcSsGetContextBinding +@ stub RpcSsGetThreadHandle +@ stub RpcSsSetClientAllocFree +@ stub RpcSsSetThreadHandle +@ stub RpcSsSwapClientAllocFree +@ stdcall RpcStringBindingComposeA(str str str str str ptr) +@ stdcall RpcStringBindingComposeW(wstr wstr wstr wstr wstr ptr) +@ stdcall RpcStringBindingParseA(str ptr ptr ptr ptr ptr) +@ stdcall RpcStringBindingParseW(wstr ptr ptr ptr ptr ptr) +@ stdcall RpcStringFreeA(ptr) +@ stdcall RpcStringFreeW(ptr) +@ stub RpcTestCancel +@ stub RpcUserFree # wxp +@ stub SimpleTypeAlignment # wxp +@ stub SimpleTypeBufferSize # wxp +@ stub SimpleTypeMemorySize # wxp +@ stub StartServiceIfNecessary # win9x +@ stdcall TowerConstruct(ptr ptr ptr ptr ptr ptr) +@ stdcall TowerExplode(ptr ptr ptr ptr ptr ptr) +@ stdcall UuidCompare(ptr ptr ptr) +@ stdcall UuidCreate(ptr) +@ stdcall UuidCreateNil(ptr) +@ stdcall UuidCreateSequential(ptr) # win 2000 +@ stdcall UuidEqual(ptr ptr ptr) +@ stdcall UuidFromStringA(str ptr) +@ stdcall UuidFromStringW(wstr ptr) +@ stdcall UuidHash(ptr ptr) +@ stdcall UuidIsNil(ptr ptr) +@ stdcall UuidToStringA(ptr ptr) +@ stdcall UuidToStringW(ptr ptr) +@ stub char_array_from_ndr +@ stub char_from_ndr +@ stub data_from_ndr +@ stub data_into_ndr +@ stub data_size_ndr +@ stub double_array_from_ndr +@ stub double_from_ndr +@ stub enum_from_ndr +@ stub float_array_from_ndr +@ stub float_from_ndr +@ stub long_array_from_ndr +@ stub long_from_ndr +@ stub long_from_ndr_temp +@ stub pfnFreeRoutines # wxp +@ stub pfnMarshallRouteines # wxp +@ stub pfnSizeRoutines # wxp +@ stub pfnUnmarshallRouteines # wxp +@ stub short_array_from_ndr +@ stub short_from_ndr +@ stub short_from_ndr_temp +@ stub tree_into_ndr +@ stub tree_peek_ndr +@ stub tree_size_ndr diff --git a/reactos/dll/win32/rpcrt4_new/rpcrt4_main.c b/reactos/dll/win32/rpcrt4_new/rpcrt4_main.c new file mode 100644 index 00000000000..513ff472054 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpcrt4_main.c @@ -0,0 +1,830 @@ +/* + * RPCRT4 + * + * Copyright 2000 Huw D M Davies 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 + * + * WINE RPC TODO's (and a few TODONT's) + * + * - Ove's decreasingly incomplete widl is an IDL compiler for wine. For widl + * to be wine's only IDL compiler, a fair bit of work remains to be done. + * until then we have used some midl-generated stuff. (What?) + * widl currently doesn't generate stub/proxy files required by wine's (O)RPC + * capabilities -- nor does it make those lovely format strings :( + * The MS MIDL compiler does some really esoteric stuff. Of course Ove has + * started with the less esoteric stuff. There are also lots of nice + * comments in there if you want to flex your bison and help build this monster. + * + * - RPC has a quite featureful error handling mechanism; basically none of this is + * implemented right now. We also have deficiencies on the compiler side, where + * wine's __TRY / __EXCEPT / __FINALLY macros are not even used for RpcTryExcept & co, + * due to syntactic differences! (we can fix it with widl by using __TRY) + * + * - There are several different memory allocation schemes for MSRPC. + * I don't even understand what they all are yet, much less have them + * properly implemented. Surely we are supposed to be doing something with + * the user-provided allocation/deallocation functions, but so far, + * I don't think we are doing this... + * + * - MSRPC provides impersonation capabilities which currently are not possible + * to implement in wine. At the very least we should implement the authorization + * API's & gracefully ignore the irrelevant stuff (to an extent we already do). + * + * - Some transports are not yet implemented. The existing transport implementations + * are incomplete and may be bug-infested. + * + * - The various transports that we do support ought to be supported in a more + * object-oriented manner, as in DCE's RPC implementation, instead of cluttering + * up the code with conditionals like we do now. + * + * - Data marshalling: So far, only the beginnings of a full implementation + * exist in wine. NDR protocol itself is documented, but the MS API's to + * convert data-types in memory into NDR are not. This is challenging work, + * and has supposedly been "at the top of Greg's queue" for several months now. + * + * - ORPC is RPC for OLE; once we have a working RPC framework, we can + * use it to implement out-of-process OLE client/server communications. + * ATM there is maybe a disconnect between the marshalling in the OLE DLLs + * and the marshalling going on here [TODO: well, is there or not?] + * + * - In-source API Documentation, at least for those functions which we have + * implemented, but preferably for everything we can document, would be nice, + * since some of this stuff is quite obscure. + * + * - Name services... [TODO: what about them] + * + * - Protocol Towers: Totally unimplemented.... I think. + * + * - Context Handle Rundown: whatever that is. + * + * - Nested RPC's: Totally unimplemented. + * + * - Statistics: we are supposed to be keeping various counters. we aren't. + * + * - Async RPC: Unimplemented. + * + * - XML/http RPC: Somewhere there's an XML fiend that wants to do this! Betcha + * we could use these as a transport for RPC's across computers without a + * permissions and/or licensing crisis. + * + * - The NT "ports" API, aka LPC. Greg claims this is on his radar. Might (or + * might not) enable users to get some kind of meaningful result out of + * NT-based native rpcrt4's. Commonly-used transport for self-to-self RPC's. + * + * - ...? More stuff I haven't thought of. If you think of more RPC todo's + * drop me an e-mail or send a patch to the + * wine-patches mailing list. + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "windef.h" +#include "winerror.h" +#include "winbase.h" +#include "winuser.h" +#include "iptypes.h" +#include "iphlpapi.h" +#include "wine/unicode.h" +#include "rpc.h" + +#include "ole2.h" +#include "rpcndr.h" +#include "rpcproxy.h" + +#include "rpc_binding.h" +#include "rpcss_np_client.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(rpc); + +static UUID uuid_nil; +static HANDLE master_mutex; + +HANDLE RPCRT4_GetMasterMutex(void) +{ + return master_mutex; +} + +static CRITICAL_SECTION uuid_cs; +static CRITICAL_SECTION_DEBUG critsect_debug = +{ + 0, 0, &uuid_cs, + { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": uuid_cs") } +}; +static CRITICAL_SECTION uuid_cs = { &critsect_debug, -1, 0, 0, 0, 0 }; + +/*********************************************************************** + * DllMain + * + * PARAMS + * hinstDLL [I] handle to the DLL's instance + * fdwReason [I] + * lpvReserved [I] reserved, must be NULL + * + * RETURNS + * Success: TRUE + * Failure: FALSE + */ + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + master_mutex = CreateMutexA( NULL, FALSE, RPCSS_MASTER_MUTEX_NAME); + if (!master_mutex) + ERR("Failed to create master mutex\n"); + break; + + case DLL_PROCESS_DETACH: + CloseHandle(master_mutex); + master_mutex = NULL; + break; + } + + return TRUE; +} + +/************************************************************************* + * RpcStringFreeA [RPCRT4.@] + * + * Frees a character string allocated by the RPC run-time library. + * + * RETURNS + * + * S_OK if successful. + */ +RPC_STATUS WINAPI RpcStringFreeA(RPC_CSTR* String) +{ + HeapFree( GetProcessHeap(), 0, *String); + + return RPC_S_OK; +} + +/************************************************************************* + * RpcStringFreeW [RPCRT4.@] + * + * Frees a character string allocated by the RPC run-time library. + * + * RETURNS + * + * S_OK if successful. + */ +RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR* String) +{ + HeapFree( GetProcessHeap(), 0, *String); + + return RPC_S_OK; +} + +/************************************************************************* + * RpcRaiseException [RPCRT4.@] + * + * Raises an exception. + */ +void WINAPI RpcRaiseException(RPC_STATUS exception) +{ + /* FIXME: translate exception? */ + RaiseException(exception, 0, 0, NULL); +} + +/************************************************************************* + * UuidCompare [RPCRT4.@] + * + * PARAMS + * UUID *Uuid1 [I] Uuid to compare + * UUID *Uuid2 [I] Uuid to compare + * RPC_STATUS *Status [O] returns RPC_S_OK + * + * RETURNS + * -1 if Uuid1 is less than Uuid2 + * 0 if Uuid1 and Uuid2 are equal + * 1 if Uuid1 is greater than Uuid2 + */ +int WINAPI UuidCompare(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) +{ + int i; + + TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); + + *Status = RPC_S_OK; + + if (!Uuid1) Uuid1 = &uuid_nil; + if (!Uuid2) Uuid2 = &uuid_nil; + + if (Uuid1 == Uuid2) return 0; + + if (Uuid1->Data1 != Uuid2->Data1) + return Uuid1->Data1 < Uuid2->Data1 ? -1 : 1; + + if (Uuid1->Data2 != Uuid2->Data2) + return Uuid1->Data2 < Uuid2->Data2 ? -1 : 1; + + if (Uuid1->Data3 != Uuid2->Data3) + return Uuid1->Data3 < Uuid2->Data3 ? -1 : 1; + + for (i = 0; i < 8; i++) { + if (Uuid1->Data4[i] < Uuid2->Data4[i]) + return -1; + if (Uuid1->Data4[i] > Uuid2->Data4[i]) + return 1; + } + + return 0; +} + +/************************************************************************* + * UuidEqual [RPCRT4.@] + * + * PARAMS + * UUID *Uuid1 [I] Uuid to compare + * UUID *Uuid2 [I] Uuid to compare + * RPC_STATUS *Status [O] returns RPC_S_OK + * + * RETURNS + * TRUE/FALSE + */ +int WINAPI UuidEqual(UUID *Uuid1, UUID *Uuid2, RPC_STATUS *Status) +{ + TRACE("(%s,%s)\n", debugstr_guid(Uuid1), debugstr_guid(Uuid2)); + return !UuidCompare(Uuid1, Uuid2, Status); +} + +/************************************************************************* + * UuidIsNil [RPCRT4.@] + * + * PARAMS + * UUID *Uuid [I] Uuid to compare + * RPC_STATUS *Status [O] retuns RPC_S_OK + * + * RETURNS + * TRUE/FALSE + */ +int WINAPI UuidIsNil(UUID *Uuid, RPC_STATUS *Status) +{ + TRACE("(%s)\n", debugstr_guid(Uuid)); + if (!Uuid) return TRUE; + return !UuidCompare(Uuid, &uuid_nil, Status); +} + + /************************************************************************* + * UuidCreateNil [RPCRT4.@] + * + * PARAMS + * UUID *Uuid [O] returns a nil UUID + * + * RETURNS + * RPC_S_OK + */ +RPC_STATUS WINAPI UuidCreateNil(UUID *Uuid) +{ + *Uuid = uuid_nil; + return RPC_S_OK; +} + +/* Number of 100ns ticks per clock tick. To be safe, assume that the clock + resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */ +#define TICKS_PER_CLOCK_TICK 1000 +#define SECSPERDAY 86400 +#define TICKSPERSEC 10000000 +/* UUID system time starts at October 15, 1582 */ +#define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY) +#define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC) + +static void RPC_UuidGetSystemTime(ULONGLONG *time) +{ + FILETIME ft; + + GetSystemTimeAsFileTime(&ft); + + *time = ((ULONGLONG)ft.dwHighDateTime << 32) | ft.dwLowDateTime; + *time += TICKS_15_OCT_1582_TO_1601; +} + +/* Assume that a hardware address is at least 6 bytes long */ +#define ADDRESS_BYTES_NEEDED 6 + +static RPC_STATUS RPC_UuidGetNodeAddress(BYTE *address) +{ + int i; + DWORD status = RPC_S_OK; + + ULONG buflen = sizeof(IP_ADAPTER_INFO); + PIP_ADAPTER_INFO adapter = HeapAlloc(GetProcessHeap(), 0, buflen); + + if (GetAdaptersInfo(adapter, &buflen) == ERROR_BUFFER_OVERFLOW) { + HeapFree(GetProcessHeap(), 0, adapter); + adapter = HeapAlloc(GetProcessHeap(), 0, buflen); + } + + if (GetAdaptersInfo(adapter, &buflen) == NO_ERROR) { + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = adapter->Address[i]; + } + } + /* We can't get a hardware address, just use random numbers. + Set the multicast bit to prevent conflicts with real cards. */ + else { + for (i = 0; i < ADDRESS_BYTES_NEEDED; i++) { + address[i] = rand() & 0xff; + } + + address[0] |= 0x01; + status = RPC_S_UUID_LOCAL_ONLY; + } + + HeapFree(GetProcessHeap(), 0, adapter); + return status; +} + +/************************************************************************* + * UuidCreate [RPCRT4.@] + * + * Creates a 128bit UUID. + * + * RETURNS + * + * RPC_S_OK if successful. + * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. + * + * FIXME: No compensation for changes across reloading + * this dll or across reboots (e.g. clock going + * backwards and swapped network cards). The RFC + * suggests using NVRAM for storing persistent + * values. + */ +RPC_STATUS WINAPI UuidCreate(UUID *Uuid) +{ + static int initialised, count; + + ULONGLONG time; + static ULONGLONG timelast; + static WORD sequence; + + static DWORD status; + static BYTE address[MAX_ADAPTER_ADDRESS_LENGTH]; + + EnterCriticalSection(&uuid_cs); + + if (!initialised) { + RPC_UuidGetSystemTime(&timelast); + count = TICKS_PER_CLOCK_TICK; + + sequence = ((rand() & 0xff) << 8) + (rand() & 0xff); + sequence &= 0x1fff; + + status = RPC_UuidGetNodeAddress(address); + initialised = 1; + } + + /* Generate time element of the UUID. Account for going faster + than our clock as well as the clock going backwards. */ + while (1) { + RPC_UuidGetSystemTime(&time); + if (time > timelast) { + count = 0; + break; + } + if (time < timelast) { + sequence = (sequence + 1) & 0x1fff; + count = 0; + break; + } + if (count < TICKS_PER_CLOCK_TICK) { + count++; + break; + } + } + + timelast = time; + time += count; + + /* Pack the information into the UUID structure. */ + + Uuid->Data1 = (unsigned long)(time & 0xffffffff); + Uuid->Data2 = (unsigned short)((time >> 32) & 0xffff); + Uuid->Data3 = (unsigned short)((time >> 48) & 0x0fff); + + /* This is a version 1 UUID */ + Uuid->Data3 |= (1 << 12); + + Uuid->Data4[0] = sequence & 0xff; + Uuid->Data4[1] = (sequence & 0x3f00) >> 8; + Uuid->Data4[1] |= 0x80; + + Uuid->Data4[2] = address[0]; + Uuid->Data4[3] = address[1]; + Uuid->Data4[4] = address[2]; + Uuid->Data4[5] = address[3]; + Uuid->Data4[6] = address[4]; + Uuid->Data4[7] = address[5]; + + LeaveCriticalSection(&uuid_cs); + + TRACE("%s\n", debugstr_guid(Uuid)); + + return status; +} + +/************************************************************************* + * UuidCreateSequential [RPCRT4.@] + * + * Creates a 128bit UUID. + * + * RETURNS + * + * RPC_S_OK if successful. + * RPC_S_UUID_LOCAL_ONLY if UUID is only locally unique. + * + */ +RPC_STATUS WINAPI UuidCreateSequential(UUID *Uuid) +{ + return UuidCreate(Uuid); +} + + +/************************************************************************* + * UuidHash [RPCRT4.@] + * + * Generates a hash value for a given UUID + * + * Code based on FreeDCE implementation + * + */ +unsigned short WINAPI UuidHash(UUID *uuid, RPC_STATUS *Status) +{ + BYTE *data = (BYTE*)uuid; + short c0 = 0, c1 = 0, x, y; + unsigned int i; + + if (!uuid) data = (BYTE*)(uuid = &uuid_nil); + + TRACE("(%s)\n", debugstr_guid(uuid)); + + for (i=0; iData1, Uuid->Data2, Uuid->Data3, + Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], + Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], + Uuid->Data4[6], Uuid->Data4[7] ); + + return RPC_S_OK; +} + +/************************************************************************* + * UuidToStringW [RPCRT4.@] + * + * Converts a UUID to a string. + * + * S_OK if successful. + * S_OUT_OF_MEMORY if unsuccessful. + */ +RPC_STATUS WINAPI UuidToStringW(UUID *Uuid, RPC_WSTR* StringUuid) +{ + char buf[37]; + + if (!Uuid) Uuid = &uuid_nil; + + sprintf(buf, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + Uuid->Data1, Uuid->Data2, Uuid->Data3, + Uuid->Data4[0], Uuid->Data4[1], Uuid->Data4[2], + Uuid->Data4[3], Uuid->Data4[4], Uuid->Data4[5], + Uuid->Data4[6], Uuid->Data4[7] ); + + *StringUuid = RPCRT4_strdupAtoW(buf); + + if(!(*StringUuid)) + return RPC_S_OUT_OF_MEMORY; + + return RPC_S_OK; +} + +static const BYTE hex2bin[] = +{ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x00 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x10 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x20 */ + 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, /* 0x30 */ + 0,10,11,12,13,14,15,0,0,0,0,0,0,0,0,0, /* 0x40 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x50 */ + 0,10,11,12,13,14,15 /* 0x60 */ +}; + +/*********************************************************************** + * UuidFromStringA (RPCRT4.@) + */ +RPC_STATUS WINAPI UuidFromStringA(RPC_CSTR s, UUID *uuid) +{ + int i; + + if (!s) return UuidCreateNil( uuid ); + + if (strlen((char*)s) != 36) return RPC_S_INVALID_STRING_UUID; + + if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) + return RPC_S_INVALID_STRING_UUID; + + for (i=0; i<36; i++) + { + if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; + if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; + } + + /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ + + uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | + hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); + uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; + uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; + + /* these are just sequential bytes */ + uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; + uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; + uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; + uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; + uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; + uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; + uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; + uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; + return RPC_S_OK; +} + + +/*********************************************************************** + * UuidFromStringW (RPCRT4.@) + */ +RPC_STATUS WINAPI UuidFromStringW(RPC_WSTR s, UUID *uuid) +{ + int i; + + if (!s) return UuidCreateNil( uuid ); + + if (strlenW(s) != 36) return RPC_S_INVALID_STRING_UUID; + + if ((s[8]!='-') || (s[13]!='-') || (s[18]!='-') || (s[23]!='-')) + return RPC_S_INVALID_STRING_UUID; + + for (i=0; i<36; i++) + { + if ((i == 8)||(i == 13)||(i == 18)||(i == 23)) continue; + if (s[i] > 'f' || (!hex2bin[s[i]] && s[i] != '0')) return RPC_S_INVALID_STRING_UUID; + } + + /* in form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ + + uuid->Data1 = (hex2bin[s[0]] << 28 | hex2bin[s[1]] << 24 | hex2bin[s[2]] << 20 | hex2bin[s[3]] << 16 | + hex2bin[s[4]] << 12 | hex2bin[s[5]] << 8 | hex2bin[s[6]] << 4 | hex2bin[s[7]]); + uuid->Data2 = hex2bin[s[9]] << 12 | hex2bin[s[10]] << 8 | hex2bin[s[11]] << 4 | hex2bin[s[12]]; + uuid->Data3 = hex2bin[s[14]] << 12 | hex2bin[s[15]] << 8 | hex2bin[s[16]] << 4 | hex2bin[s[17]]; + + /* these are just sequential bytes */ + uuid->Data4[0] = hex2bin[s[19]] << 4 | hex2bin[s[20]]; + uuid->Data4[1] = hex2bin[s[21]] << 4 | hex2bin[s[22]]; + uuid->Data4[2] = hex2bin[s[24]] << 4 | hex2bin[s[25]]; + uuid->Data4[3] = hex2bin[s[26]] << 4 | hex2bin[s[27]]; + uuid->Data4[4] = hex2bin[s[28]] << 4 | hex2bin[s[29]]; + uuid->Data4[5] = hex2bin[s[30]] << 4 | hex2bin[s[31]]; + uuid->Data4[6] = hex2bin[s[32]] << 4 | hex2bin[s[33]]; + uuid->Data4[7] = hex2bin[s[34]] << 4 | hex2bin[s[35]]; + return RPC_S_OK; +} + +/*********************************************************************** + * DllRegisterServer (RPCRT4.@) + */ + +HRESULT WINAPI DllRegisterServer( void ) +{ + FIXME( "(): stub\n" ); + return S_OK; +} + +static BOOL RPCRT4_StartRPCSS(void) +{ + PROCESS_INFORMATION pi; + STARTUPINFOA si; + static char cmd[6]; + BOOL rslt; + + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFOA)); + si.cb = sizeof(STARTUPINFOA); + + /* apparently it's not OK to use a constant string below */ + CopyMemory(cmd, "rpcss", 6); + + /* FIXME: will this do the right thing when run as a test? */ + rslt = CreateProcessA( + NULL, /* executable */ + cmd, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + FALSE, /* inherit handles */ + 0, /* creation flags */ + NULL, /* use parent's environment */ + NULL, /* use parent's current directory */ + &si, /* STARTUPINFO pointer */ + &pi /* PROCESS_INFORMATION */ + ); + + if (rslt) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + + return rslt; +} + +/*********************************************************************** + * RPCRT4_RPCSSOnDemandCall (internal) + * + * Attempts to send a message to the RPCSS process + * on the local machine, invoking it if necessary. + * For remote RPCSS calls, use.... your imagination. + * + * PARAMS + * msg [I] pointer to the RPCSS message + * vardata_payload [I] pointer vardata portion of the RPCSS message + * reply [O] pointer to reply structure + * + * RETURNS + * TRUE if successful + * FALSE otherwise + */ +BOOL RPCRT4_RPCSSOnDemandCall(PRPCSS_NP_MESSAGE msg, char *vardata_payload, PRPCSS_NP_REPLY reply) +{ + HANDLE client_handle; + BOOL ret; + int i, j = 0; + + TRACE("(msg == %p, vardata_payload == %p, reply == %p)\n", msg, vardata_payload, reply); + + client_handle = RPCRT4_RpcssNPConnect(); + + while (INVALID_HANDLE_VALUE == client_handle) { + /* start the RPCSS process */ + if (!RPCRT4_StartRPCSS()) { + ERR("Unable to start RPCSS process.\n"); + return FALSE; + } + /* wait for a connection (w/ periodic polling) */ + for (i = 0; i < 60; i++) { + Sleep(200); + client_handle = RPCRT4_RpcssNPConnect(); + if (INVALID_HANDLE_VALUE != client_handle) break; + } + /* we are only willing to try twice */ + if (j++ >= 1) break; + } + + if (INVALID_HANDLE_VALUE == client_handle) { + /* no dice! */ + ERR("Unable to connect to RPCSS process!\n"); + SetLastError(RPC_E_SERVER_DIED_DNE); + return FALSE; + } + + /* great, we're connected. now send the message */ + ret = TRUE; + if (!RPCRT4_SendReceiveNPMsg(client_handle, msg, vardata_payload, reply)) { + ERR("Something is amiss: RPC_SendReceive failed.\n"); + ret = FALSE; + } + CloseHandle(client_handle); + + return ret; +} + +#define MAX_RPC_ERROR_TEXT 256 + +/****************************************************************************** + * DceErrorInqTextW (rpcrt4.@) + * + * Notes + * 1. On passing a NULL pointer the code does bomb out. + * 2. The size of the required buffer is not defined in the documentation. + * It appears to be 256. + * 3. The function is defined to return RPC_S_INVALID_ARG but I don't know + * of any value for which it does. + * 4. The MSDN documentation currently declares that the second argument is + * unsigned char *, even for the W version. I don't believe it. + */ +RPC_STATUS RPC_ENTRY DceErrorInqTextW (RPC_STATUS e, RPC_WSTR buffer) +{ + DWORD count; + count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, e, 0, buffer, MAX_RPC_ERROR_TEXT, NULL); + if (!count) + { + count = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, RPC_S_NOT_RPC_ERROR, 0, buffer, MAX_RPC_ERROR_TEXT, NULL); + if (!count) + { + ERR ("Failed to translate error\n"); + return RPC_S_INVALID_ARG; + } + } + return RPC_S_OK; +} + +/****************************************************************************** + * DceErrorInqTextA (rpcrt4.@) + */ +RPC_STATUS RPC_ENTRY DceErrorInqTextA (RPC_STATUS e, RPC_CSTR buffer) +{ + RPC_STATUS status; + WCHAR bufferW [MAX_RPC_ERROR_TEXT]; + if ((status = DceErrorInqTextW (e, bufferW)) == RPC_S_OK) + { + if (!WideCharToMultiByte(CP_ACP, 0, bufferW, -1, (LPSTR)buffer, MAX_RPC_ERROR_TEXT, + NULL, NULL)) + { + ERR ("Failed to translate error\n"); + status = RPC_S_INVALID_ARG; + } + } + return status; +} + +/****************************************************************************** + * I_RpcAllocate (rpcrt4.@) + */ +void * WINAPI I_RpcAllocate(unsigned int Size) +{ + return HeapAlloc(GetProcessHeap(), 0, Size); +} + +/****************************************************************************** + * I_RpcFree (rpcrt4.@) + */ +void WINAPI I_RpcFree(void *Object) +{ + HeapFree(GetProcessHeap(), 0, Object); +} + +/****************************************************************************** + * I_RpcMapWin32Status (rpcrt4.@) + */ +DWORD WINAPI I_RpcMapWin32Status(RPC_STATUS status) +{ + FIXME("(%ld): stub\n", status); + return 0; +} diff --git a/reactos/dll/win32/rpcrt4_new/rpcss_np_client.c b/reactos/dll/win32/rpcrt4_new/rpcss_np_client.c new file mode 100644 index 00000000000..016f77f5f15 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpcss_np_client.c @@ -0,0 +1,152 @@ +/* + * RPCSS named pipe client implementation + * + * Copyright (C) 2002 Greg Turner + * + * 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 "wine/rpcss_shared.h" +#include "wine/debug.h" + +#include "rpc_binding.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +HANDLE RPCRT4_RpcssNPConnect(void) +{ + HANDLE the_pipe; + DWORD dwmode, wait_result; + HANDLE master_mutex = RPCRT4_GetMasterMutex(); + + TRACE("\n"); + + while (TRUE) { + + wait_result = WaitForSingleObject(master_mutex, MASTER_MUTEX_TIMEOUT); + switch (wait_result) { + case WAIT_ABANDONED: + case WAIT_OBJECT_0: + break; + case WAIT_FAILED: + case WAIT_TIMEOUT: + default: + ERR("This should never happen: couldn't enter mutex.\n"); + return NULL; + } + + /* try to open the client side of the named pipe. */ + the_pipe = CreateFileA( + NAME_RPCSS_NAMED_PIPE, /* pipe name */ + GENERIC_READ | GENERIC_WRITE, /* r/w access */ + 0, /* no sharing */ + NULL, /* no security attributes */ + OPEN_EXISTING, /* open an existing pipe */ + 0, /* default attributes */ + NULL /* no template file */ + ); + + if (the_pipe != INVALID_HANDLE_VALUE) + break; + + if (GetLastError() != ERROR_PIPE_BUSY) { + WARN("Unable to open named pipe %s (assuming unavailable).\n", + debugstr_a(NAME_RPCSS_NAMED_PIPE)); + break; + } + + WARN("Named pipe busy (will wait)\n"); + + if (!ReleaseMutex(master_mutex)) + ERR("Failed to release master mutex. Expect deadlock.\n"); + + /* wait for the named pipe. We are only willing to wait for 5 seconds. + It should be available /very/ soon. */ + if (! WaitNamedPipeA(NAME_RPCSS_NAMED_PIPE, MASTER_MUTEX_WAITNAMEDPIPE_TIMEOUT)) + { + ERR("Named pipe unavailable after waiting. Something is probably wrong.\n"); + break; + } + + } + + if (the_pipe != INVALID_HANDLE_VALUE) { + dwmode = PIPE_READMODE_MESSAGE; + /* SetNamedPipeHandleState not implemented ATM, but still seems to work somehow. */ + if (! SetNamedPipeHandleState(the_pipe, &dwmode, NULL, NULL)) + WARN("Failed to set pipe handle state\n"); + } + + if (!ReleaseMutex(master_mutex)) + ERR("Uh oh, failed to leave the RPC Master Mutex!\n"); + + return the_pipe; +} + +BOOL RPCRT4_SendReceiveNPMsg(HANDLE np, PRPCSS_NP_MESSAGE msg, char *vardata, PRPCSS_NP_REPLY reply) +{ + DWORD count; + UINT32 payload_offset; + RPCSS_NP_MESSAGE vardata_payload_msg; + + TRACE("(np == %p, msg == %p, vardata == %p, reply == %p)\n", + np, msg, vardata, reply); + + if (! WriteFile(np, msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + ERR("write failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_MESSAGE)) { + ERR("write count mismatch.\n"); + return FALSE; + } + + /* process the vardata payload if necessary */ + vardata_payload_msg.message_type = RPCSS_NP_MESSAGE_TYPEID_VARDATAPAYLOADMSG; + vardata_payload_msg.vardata_payload_size = 0; /* meaningless */ + for ( payload_offset = 0; payload_offset < msg->vardata_payload_size; + payload_offset += VARDATA_PAYLOAD_BYTES ) { + TRACE("sending vardata payload. vd=%p, po=%d, ps=%d\n", vardata, + payload_offset, msg->vardata_payload_size); + ZeroMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, VARDATA_PAYLOAD_BYTES); + CopyMemory(vardata_payload_msg.message.vardatapayloadmsg.payload, + vardata, + min( VARDATA_PAYLOAD_BYTES, msg->vardata_payload_size - payload_offset )); + vardata += VARDATA_PAYLOAD_BYTES; + if (! WriteFile(np, &vardata_payload_msg, sizeof(RPCSS_NP_MESSAGE), &count, NULL)) { + ERR("vardata write failed at %u bytes.\n", payload_offset); + return FALSE; + } + } + + if (! ReadFile(np, reply, sizeof(RPCSS_NP_REPLY), &count, NULL)) { + ERR("read failed.\n"); + return FALSE; + } + + if (count != sizeof(RPCSS_NP_REPLY)) { + ERR("read count mismatch. got %d.\n", count); + return FALSE; + } + + /* message execution was successful */ + return TRUE; +} diff --git a/reactos/dll/win32/rpcrt4_new/rpcss_np_client.h b/reactos/dll/win32/rpcrt4_new/rpcss_np_client.h new file mode 100644 index 00000000000..db65d432bca --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/rpcss_np_client.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2002 Greg Turner + * + * 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 + */ + +#ifndef __WINE_RPCSS_NP_CLIENT_H +#define __WINE_RPCSS_NP_CLIENT_H + +/* rpcss_np_client.c */ +HANDLE RPC_RpcssNPConnect(void); +BOOL RPCRT4_SendReceiveNPMsg(HANDLE, PRPCSS_NP_MESSAGE, char *, PRPCSS_NP_REPLY); + +#endif /* __RPCSS_NP_CLINET_H */ diff --git a/reactos/dll/win32/rpcrt4_new/unix_func.c b/reactos/dll/win32/rpcrt4_new/unix_func.c new file mode 100644 index 00000000000..490f10c9ac0 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/unix_func.c @@ -0,0 +1,169 @@ +#include +#include +#include +#include +#include "unix_func.h" + + +int +poll(struct pollfd *fds, + unsigned long nfds, + int timo) +{ + TIMEVAL timeout, *toptr; + FD_SET ifds, ofds, efds, *ip, *op; + int i, rc, n = -1; + + ip = op = NULL; + + FD_ZERO(&ifds); + FD_ZERO(&ofds); + FD_ZERO(&efds); + + for (i = 0; i < nfds; ++i) + { + fds[i].revents = 0; + + if (fds[i].fd < 0) + continue; + + if (fds[i].fd > n) + n = fds[i].fd; + + if (fds[i].events & (POLLIN|POLLPRI)) + { + ip = &ifds; + FD_SET(fds[i].fd, ip); + } + + if (fds[i].events & POLLOUT) + { + op = &ofds; + FD_SET(fds[i].fd, op); + } + + FD_SET(fds[i].fd, &efds); + } + + if (timo < 0) + toptr = 0; + else + { + toptr = &timeout; + timeout.tv_sec = timo / 1000; + timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000; + } + + rc = select(++n, ip, op, &efds, toptr); + + if (rc <= 0) + return rc; + + for (i = 0, n = 0; i < nfds; ++i) + { + if (fds[i].fd < 0) continue; + + if (fds[i].events & (POLLIN|POLLPRI) && FD_ISSET(i, &ifds)) + fds[i].revents |= POLLIN; + + if (fds[i].events & POLLOUT && FD_ISSET(i, &ofds)) + fds[i].revents |= POLLOUT; + + if (FD_ISSET(i, &efds)) + fds[i].revents |= POLLHUP; + } + + return rc; +} + + +int socketpair(int af, + int type, + int protocol, + SOCKET socks[2]) +{ + struct sockaddr_in addr; + SOCKET listener; + int e; + int addrlen = sizeof(addr); + DWORD flags = 0; //(make_overlapped ? WSA_FLAG_OVERLAPPED : 0); + + if (socks == 0) + { + WSASetLastError(WSAEINVAL); + return SOCKET_ERROR; + } + + socks[0] = socks[1] = INVALID_SOCKET; + if ((listener = socket(af, type, 0)) == INVALID_SOCKET) + return SOCKET_ERROR; + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(0x7f000001); + addr.sin_port = 0; + + e = bind(listener, (const struct sockaddr*) &addr, sizeof(addr)); + if (e == SOCKET_ERROR) + { + e = WSAGetLastError(); + closesocket(listener); + WSASetLastError(e); + return SOCKET_ERROR; + } + e = getsockname(listener, (struct sockaddr*) &addr, &addrlen); + if (e == SOCKET_ERROR) + { + e = WSAGetLastError(); + closesocket(listener); + WSASetLastError(e); + return SOCKET_ERROR; + } + + do + { + if (listen(listener, 1) == SOCKET_ERROR) + break; + if ((socks[0] = WSASocket(af, type, 0, NULL, 0, flags)) == INVALID_SOCKET) + break; + if (connect(socks[0], (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) + break; + if ((socks[1] = accept(listener, NULL, NULL)) == INVALID_SOCKET) + break; + + closesocket(listener); + return 0; + + } while (0); + + e = WSAGetLastError(); + closesocket(listener); + closesocket(socks[0]); + closesocket(socks[1]); + WSASetLastError(e); + return SOCKET_ERROR; +} + + +const char * +inet_ntop (int af, + const void *src, + char *dst, + size_t cnt) +{ + struct in_addr in; + char *text_addr; + + if (af == AF_INET) + { + memcpy(&in.s_addr, src, sizeof(in.s_addr)); + text_addr = inet_ntoa(in); + if (text_addr && dst) + { + strncpy(dst, text_addr, cnt); + return dst; + } + } + + return 0; +} diff --git a/reactos/dll/win32/rpcrt4_new/unix_func.h b/reactos/dll/win32/rpcrt4_new/unix_func.h new file mode 100644 index 00000000000..bfdad0df270 --- /dev/null +++ b/reactos/dll/win32/rpcrt4_new/unix_func.h @@ -0,0 +1,19 @@ + +#define POLLIN 001 +#define POLLPRI 002 +#define POLLOUT 004 +#define POLLNORM POLLIN +#define POLLERR 010 +#define POLLHUP 020 +#define POLLNVAL 040 + +struct pollfd +{ + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; + +int poll(struct pollfd *fds, unsigned long nfds, int timo); +int socketpair (int af, int type, int protocol, SOCKET socket[2]); +const char * inet_ntop (int af, const void *src, char *dst, size_t cnt);