dmstyle: Assign to structs instead of using memcpy.
[wine] / dlls / rpcrt4 / ndr_contexthandle.c
1 /*
2  * NDR data marshalling
3  *
4  * Copyright 2006 Mike McCormack (for CodeWeavers)
5  * Copyright 2006-2007 Robert Shearman (for CodeWeavers)
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "ndr_misc.h"
23 #include "rpc_assoc.h"
24 #include "rpcndr.h"
25
26 #include "wine/rpcfc.h"
27
28 #include "wine/debug.h"
29 #include "wine/list.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(ole);
32
33 #define NDR_CONTEXT_HANDLE_MAGIC 0x4352444e
34
35 typedef struct ndr_context_handle
36 {
37     ULONG      attributes;
38     GUID       uuid;
39 } ndr_context_handle;
40
41 struct context_handle_entry
42 {
43     struct list entry;
44     DWORD magic;
45     RPC_BINDING_HANDLE handle;
46     ndr_context_handle wire_data;
47 };
48
49 static struct list context_handle_list = LIST_INIT(context_handle_list);
50
51 static CRITICAL_SECTION ndr_context_cs;
52 static CRITICAL_SECTION_DEBUG ndr_context_debug =
53 {
54     0, 0, &ndr_context_cs,
55     { &ndr_context_debug.ProcessLocksList, &ndr_context_debug.ProcessLocksList },
56       0, 0, { (DWORD_PTR)(__FILE__ ": ndr_context") }
57 };
58 static CRITICAL_SECTION ndr_context_cs = { &ndr_context_debug, -1, 0, 0, 0, 0 };
59
60 static struct context_handle_entry *get_context_entry(NDR_CCONTEXT CContext)
61 {
62     struct context_handle_entry *che = (struct context_handle_entry*) CContext;
63
64     if (che->magic != NDR_CONTEXT_HANDLE_MAGIC)
65         return NULL;
66     return che;
67 }
68
69 static struct context_handle_entry *context_entry_from_guid(LPCGUID uuid)
70 {
71     struct context_handle_entry *che;
72     LIST_FOR_EACH_ENTRY(che, &context_handle_list, struct context_handle_entry, entry)
73         if (IsEqualGUID(&che->wire_data.uuid, uuid))
74             return che;
75     return NULL;
76 }
77
78 RPC_BINDING_HANDLE WINAPI NDRCContextBinding(NDR_CCONTEXT CContext)
79 {
80     struct context_handle_entry *che;
81     RPC_BINDING_HANDLE handle = NULL;
82
83     TRACE("%p\n", CContext);
84
85     EnterCriticalSection(&ndr_context_cs);
86     che = get_context_entry(CContext);
87     if (che)
88         handle = che->handle;
89     LeaveCriticalSection(&ndr_context_cs);
90
91     if (!handle)
92         RpcRaiseException(ERROR_INVALID_HANDLE);
93     return handle;
94 }
95
96 void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
97 {
98     struct context_handle_entry *che;
99
100     TRACE("%p %p\n", CContext, pBuff);
101
102     if (CContext)
103     {
104         EnterCriticalSection(&ndr_context_cs);
105         che = get_context_entry(CContext);
106         memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
107         LeaveCriticalSection(&ndr_context_cs);
108     }
109     else
110     {
111         ndr_context_handle *wire_data = (ndr_context_handle *)pBuff;
112         wire_data->attributes = 0;
113         wire_data->uuid = GUID_NULL;
114     }
115 }
116
117 /***********************************************************************
118  *           RpcSmDestroyClientContext [RPCRT4.@]
119  */
120 RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
121 {
122     RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
123     struct context_handle_entry *che = NULL;
124
125     TRACE("(%p)\n", ContextHandle);
126
127     EnterCriticalSection(&ndr_context_cs);
128     che = get_context_entry(*ContextHandle);
129     *ContextHandle = NULL;
130     if (che)
131     {
132         status = RPC_S_OK;
133         list_remove(&che->entry);
134     }
135
136     LeaveCriticalSection(&ndr_context_cs);
137
138     if (che)
139     {
140         RpcBindingFree(&che->handle);
141         HeapFree(GetProcessHeap(), 0, che);
142     }
143
144     return status;
145 }
146
147 /***********************************************************************
148  *           RpcSsDestroyClientContext [RPCRT4.@]
149  */
150 void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
151 {
152     RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
153     if (status != RPC_S_OK)
154         RpcRaiseException(status);
155 }
156
157 static UINT ndr_update_context_handle(NDR_CCONTEXT *CContext,
158                                       RPC_BINDING_HANDLE hBinding,
159                                       const ndr_context_handle *chi)
160 {
161     struct context_handle_entry *che = NULL;
162
163     /* a null UUID means we should free the context handle */
164     if (IsEqualGUID(&chi->uuid, &GUID_NULL))
165     {
166         if (*CContext)
167         {
168             che = get_context_entry(*CContext);
169             if (!che)
170                 return ERROR_INVALID_HANDLE;
171             list_remove(&che->entry);
172             RpcBindingFree(&che->handle);
173             HeapFree(GetProcessHeap(), 0, che);
174             che = NULL;
175         }
176     }
177     /* if there's no existing entry matching the GUID, allocate one */
178     else if (!(che = context_entry_from_guid(&chi->uuid)))
179     {
180         che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
181         if (!che)
182             return ERROR_NOT_ENOUGH_MEMORY;
183         che->magic = NDR_CONTEXT_HANDLE_MAGIC;
184         RpcBindingCopy(hBinding, &che->handle);
185         list_add_tail(&context_handle_list, &che->entry);
186         memcpy(&che->wire_data, chi, sizeof *chi);
187     }
188
189     *CContext = che;
190
191     return ERROR_SUCCESS;
192 }
193
194 /***********************************************************************
195  *           NDRCContextUnmarshall [RPCRT4.@]
196  */
197 void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
198                                   RPC_BINDING_HANDLE hBinding,
199                                   void *pBuff, ULONG DataRepresentation)
200 {
201     UINT r;
202
203     TRACE("*%p=(%p) %p %p %08x\n",
204           CContext, *CContext, hBinding, pBuff, DataRepresentation);
205
206     EnterCriticalSection(&ndr_context_cs);
207     r = ndr_update_context_handle(CContext, hBinding, pBuff);
208     LeaveCriticalSection(&ndr_context_cs);
209     if (r)
210         RpcRaiseException(r);
211 }
212
213 /***********************************************************************
214  *           NDRSContextMarshall [RPCRT4.@]
215  */
216 void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
217                                void *pBuff,
218                                NDR_RUNDOWN userRunDownIn)
219 {
220     TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
221     NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff,
222                          userRunDownIn, NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
223 }
224
225 /***********************************************************************
226  *           NDRSContextMarshallEx [RPCRT4.@]
227  */
228 void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
229                                   NDR_SCONTEXT SContext,
230                                   void *pBuff,
231                                   NDR_RUNDOWN userRunDownIn)
232 {
233     TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
234     NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL,
235                          RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
236 }
237
238 /***********************************************************************
239  *           NDRSContextMarshall2 [RPCRT4.@]
240  */
241 void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
242                                  NDR_SCONTEXT SContext,
243                                  void *pBuff,
244                                  NDR_RUNDOWN userRunDownIn,
245                                  void *CtxGuard, ULONG Flags)
246 {
247     RpcBinding *binding = hBinding;
248     RPC_STATUS status;
249     ndr_context_handle *ndr = pBuff;
250
251     TRACE("(%p %p %p %p %p %u)\n",
252           hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
253
254     if (!binding->server || !binding->Assoc)
255         RpcRaiseException(ERROR_INVALID_HANDLE);
256
257     if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
258         FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
259
260     if (SContext->userContext)
261     {
262         status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
263         if (status != RPC_S_OK)
264             RpcRaiseException(status);
265         ndr->attributes = 0;
266         RpcContextHandle_GetUuid(SContext, &ndr->uuid);
267
268         RPCRT4_RemoveThreadContextHandle(SContext);
269         RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
270     }
271     else
272     {
273         if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
274             RpcRaiseException(ERROR_INVALID_HANDLE);
275         memset(ndr, 0, sizeof(*ndr));
276
277         RPCRT4_RemoveThreadContextHandle(SContext);
278         /* Note: release the context handle twice in this case to release
279          * one ref being kept around for the data and one ref for the
280          * unmarshall/marshall sequence */
281         if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE))
282             return; /* this is to cope with the case of the data not being valid
283                      * before and so not having a further reference */
284         RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE);
285     }
286 }
287
288 /***********************************************************************
289  *           NDRSContextUnmarshall [RPCRT4.@]
290  */
291 NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
292                                           ULONG DataRepresentation)
293 {
294     TRACE("(%p %08x)\n", pBuff, DataRepresentation);
295     return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff,
296                                   DataRepresentation, NULL,
297                                   RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
298 }
299
300 /***********************************************************************
301  *           NDRSContextUnmarshallEx [RPCRT4.@]
302  */
303 NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
304                                             void *pBuff,
305                                             ULONG DataRepresentation)
306 {
307     TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
308     return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL,
309                                   RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
310 }
311
312 /***********************************************************************
313  *           NDRSContextUnmarshall2 [RPCRT4.@]
314  */
315 NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
316                                            void *pBuff,
317                                            ULONG DataRepresentation,
318                                            void *CtxGuard, ULONG Flags)
319 {
320     RpcBinding *binding = hBinding;
321     NDR_SCONTEXT SContext;
322     RPC_STATUS status;
323     const ndr_context_handle *context_ndr = pBuff;
324
325     TRACE("(%p %p %08x %p %u)\n",
326           hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
327
328     if (!binding->server || !binding->Assoc)
329         RpcRaiseException(ERROR_INVALID_HANDLE);
330
331     if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
332         FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
333
334     if (!pBuff || (!context_ndr->attributes &&
335                    UuidIsNil((UUID *)&context_ndr->uuid, &status)))
336         status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
337                                                       &SContext);
338     else
339     {
340         if (context_ndr->attributes)
341         {
342             ERR("non-null attributes 0x%x\n", context_ndr->attributes);
343             status = ERROR_INVALID_HANDLE;
344         }
345         else
346             status = RpcServerAssoc_FindContextHandle(binding->Assoc,
347                                                       &context_ndr->uuid,
348                                                       CtxGuard, Flags,
349                                                       &SContext);
350     }
351
352     if (status != RPC_S_OK)
353         RpcRaiseException(status);
354
355     RPCRT4_PushThreadContextHandle(SContext);
356     return SContext;
357 }