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 } 369