[RPCRT4] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / 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 = 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 {
93 ERR("invalid handle %p\n", CContext);
94 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
95 }
96 return handle;
97 }
98
99 void WINAPI NDRCContextMarshall(NDR_CCONTEXT CContext, void *pBuff)
100 {
101 struct context_handle_entry *che;
102
103 TRACE("%p %p\n", CContext, pBuff);
104
105 if (CContext)
106 {
107 EnterCriticalSection(&ndr_context_cs);
108 che = get_context_entry(CContext);
109 memcpy(pBuff, &che->wire_data, sizeof (ndr_context_handle));
110 LeaveCriticalSection(&ndr_context_cs);
111 }
112 else
113 {
114 ndr_context_handle *wire_data = pBuff;
115 wire_data->attributes = 0;
116 wire_data->uuid = GUID_NULL;
117 }
118 }
119
120 /***********************************************************************
121 * RpcSmDestroyClientContext [RPCRT4.@]
122 */
123 RPC_STATUS WINAPI RpcSmDestroyClientContext(void **ContextHandle)
124 {
125 RPC_STATUS status = RPC_X_SS_CONTEXT_MISMATCH;
126 struct context_handle_entry *che = NULL;
127
128 TRACE("(%p)\n", ContextHandle);
129
130 EnterCriticalSection(&ndr_context_cs);
131 che = get_context_entry(*ContextHandle);
132 *ContextHandle = NULL;
133 if (che)
134 {
135 status = RPC_S_OK;
136 list_remove(&che->entry);
137 }
138
139 LeaveCriticalSection(&ndr_context_cs);
140
141 if (che)
142 {
143 RpcBindingFree(&che->handle);
144 HeapFree(GetProcessHeap(), 0, che);
145 }
146
147 return status;
148 }
149
150 /***********************************************************************
151 * RpcSsDestroyClientContext [RPCRT4.@]
152 */
153 void WINAPI RpcSsDestroyClientContext(void **ContextHandle)
154 {
155 RPC_STATUS status = RpcSmDestroyClientContext(ContextHandle);
156 if (status != RPC_S_OK)
157 RpcRaiseException(status);
158 }
159
160 /***********************************************************************
161 * RpcSsDontSerializeContext [RPCRT4.@]
162 */
163 void WINAPI RpcSsDontSerializeContext(void)
164 {
165 FIXME("stub\n");
166 }
167
168 static RPC_STATUS ndr_update_context_handle(NDR_CCONTEXT *CContext,
169 RPC_BINDING_HANDLE hBinding,
170 const ndr_context_handle *chi)
171 {
172 struct context_handle_entry *che = NULL;
173
174 /* a null UUID means we should free the context handle */
175 if (IsEqualGUID(&chi->uuid, &GUID_NULL))
176 {
177 if (*CContext)
178 {
179 che = get_context_entry(*CContext);
180 if (!che)
181 return RPC_X_SS_CONTEXT_MISMATCH;
182 list_remove(&che->entry);
183 RpcBindingFree(&che->handle);
184 HeapFree(GetProcessHeap(), 0, che);
185 che = NULL;
186 }
187 }
188 /* if there's no existing entry matching the GUID, allocate one */
189 else if (!(che = context_entry_from_guid(&chi->uuid)))
190 {
191 che = HeapAlloc(GetProcessHeap(), 0, sizeof *che);
192 if (!che)
193 return RPC_X_NO_MEMORY;
194 che->magic = NDR_CONTEXT_HANDLE_MAGIC;
195 RpcBindingCopy(hBinding, &che->handle);
196 list_add_tail(&context_handle_list, &che->entry);
197 che->wire_data = *chi;
198 }
199
200 *CContext = che;
201
202 return RPC_S_OK;
203 }
204
205 /***********************************************************************
206 * NDRCContextUnmarshall [RPCRT4.@]
207 */
208 void WINAPI NDRCContextUnmarshall(NDR_CCONTEXT *CContext,
209 RPC_BINDING_HANDLE hBinding,
210 void *pBuff, ULONG DataRepresentation)
211 {
212 RPC_STATUS status;
213
214 TRACE("*%p=(%p) %p %p %08x\n",
215 CContext, *CContext, hBinding, pBuff, DataRepresentation);
216
217 EnterCriticalSection(&ndr_context_cs);
218 status = ndr_update_context_handle(CContext, hBinding, pBuff);
219 LeaveCriticalSection(&ndr_context_cs);
220 if (status)
221 RpcRaiseException(status);
222 }
223
224 /***********************************************************************
225 * NDRSContextMarshall [RPCRT4.@]
226 */
227 void WINAPI NDRSContextMarshall(NDR_SCONTEXT SContext,
228 void *pBuff,
229 NDR_RUNDOWN userRunDownIn)
230 {
231 TRACE("(%p %p %p)\n", SContext, pBuff, userRunDownIn);
232 NDRSContextMarshall2(I_RpcGetCurrentCallHandle(), SContext, pBuff,
233 userRunDownIn, NULL, RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
234 }
235
236 /***********************************************************************
237 * NDRSContextMarshallEx [RPCRT4.@]
238 */
239 void WINAPI NDRSContextMarshallEx(RPC_BINDING_HANDLE hBinding,
240 NDR_SCONTEXT SContext,
241 void *pBuff,
242 NDR_RUNDOWN userRunDownIn)
243 {
244 TRACE("(%p %p %p %p)\n", hBinding, SContext, pBuff, userRunDownIn);
245 NDRSContextMarshall2(hBinding, SContext, pBuff, userRunDownIn, NULL,
246 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
247 }
248
249 /***********************************************************************
250 * NDRSContextMarshall2 [RPCRT4.@]
251 */
252 void WINAPI NDRSContextMarshall2(RPC_BINDING_HANDLE hBinding,
253 NDR_SCONTEXT SContext,
254 void *pBuff,
255 NDR_RUNDOWN userRunDownIn,
256 void *CtxGuard, ULONG Flags)
257 {
258 RpcBinding *binding = hBinding;
259 RPC_STATUS status;
260 ndr_context_handle *ndr = pBuff;
261
262 TRACE("(%p %p %p %p %p %u)\n",
263 hBinding, SContext, pBuff, userRunDownIn, CtxGuard, Flags);
264
265 if (!binding->server || !binding->Assoc)
266 RpcRaiseException(RPC_S_INVALID_BINDING);
267
268 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
269 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
270
271 if (SContext->userContext)
272 {
273 status = RpcServerAssoc_UpdateContextHandle(binding->Assoc, SContext, CtxGuard, userRunDownIn);
274 if (status != RPC_S_OK)
275 RpcRaiseException(status);
276 ndr->attributes = 0;
277 RpcContextHandle_GetUuid(SContext, &ndr->uuid);
278
279 RPCRT4_RemoveThreadContextHandle(SContext);
280 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE);
281 }
282 else
283 {
284 if (!RpcContextHandle_IsGuardCorrect(SContext, CtxGuard))
285 RpcRaiseException(RPC_X_SS_CONTEXT_MISMATCH);
286 memset(ndr, 0, sizeof(*ndr));
287
288 RPCRT4_RemoveThreadContextHandle(SContext);
289 /* Note: release the context handle twice in this case to release
290 * one ref being kept around for the data and one ref for the
291 * unmarshall/marshall sequence */
292 if (!RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, TRUE))
293 return; /* this is to cope with the case of the data not being valid
294 * before and so not having a further reference */
295 RpcServerAssoc_ReleaseContextHandle(binding->Assoc, SContext, FALSE);
296 }
297 }
298
299 /***********************************************************************
300 * NDRSContextUnmarshall [RPCRT4.@]
301 */
302 NDR_SCONTEXT WINAPI NDRSContextUnmarshall(void *pBuff,
303 ULONG DataRepresentation)
304 {
305 TRACE("(%p %08x)\n", pBuff, DataRepresentation);
306 return NDRSContextUnmarshall2(I_RpcGetCurrentCallHandle(), pBuff,
307 DataRepresentation, NULL,
308 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
309 }
310
311 /***********************************************************************
312 * NDRSContextUnmarshallEx [RPCRT4.@]
313 */
314 NDR_SCONTEXT WINAPI NDRSContextUnmarshallEx(RPC_BINDING_HANDLE hBinding,
315 void *pBuff,
316 ULONG DataRepresentation)
317 {
318 TRACE("(%p %p %08x)\n", hBinding, pBuff, DataRepresentation);
319 return NDRSContextUnmarshall2(hBinding, pBuff, DataRepresentation, NULL,
320 RPC_CONTEXT_HANDLE_DEFAULT_FLAGS);
321 }
322
323 /***********************************************************************
324 * NDRSContextUnmarshall2 [RPCRT4.@]
325 */
326 NDR_SCONTEXT WINAPI NDRSContextUnmarshall2(RPC_BINDING_HANDLE hBinding,
327 void *pBuff,
328 ULONG DataRepresentation,
329 void *CtxGuard, ULONG Flags)
330 {
331 RpcBinding *binding = hBinding;
332 NDR_SCONTEXT SContext;
333 RPC_STATUS status;
334 const ndr_context_handle *context_ndr = pBuff;
335
336 TRACE("(%p %p %08x %p %u)\n",
337 hBinding, pBuff, DataRepresentation, CtxGuard, Flags);
338
339 if (!binding->server || !binding->Assoc)
340 RpcRaiseException(RPC_S_INVALID_BINDING);
341
342 if (Flags & RPC_CONTEXT_HANDLE_FLAGS)
343 FIXME("unimplemented flags: 0x%x\n", Flags & RPC_CONTEXT_HANDLE_FLAGS);
344
345 if (!pBuff || (!context_ndr->attributes &&
346 UuidIsNil((UUID *)&context_ndr->uuid, &status)))
347 status = RpcServerAssoc_AllocateContextHandle(binding->Assoc, CtxGuard,
348 &SContext);
349 else
350 {
351 if (context_ndr->attributes)
352 {
353 ERR("non-null attributes 0x%x\n", context_ndr->attributes);
354 status = RPC_X_SS_CONTEXT_MISMATCH;
355 }
356 else
357 status = RpcServerAssoc_FindContextHandle(binding->Assoc,
358 &context_ndr->uuid,
359 CtxGuard, Flags,
360 &SContext);
361 }
362
363 if (status != RPC_S_OK)
364 RpcRaiseException(status);
365
366 RPCRT4_PushThreadContextHandle(SContext);
367 return SContext;
368 }