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