reshuffling of dlls
[reactos.git] / reactos / dll / win32 / rpcrt4 / rpc_binding.c
1 /*
2 * RPC binding API
3 *
4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * TODO:
23 * - a whole lot
24 */
25
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winerror.h"
35 #include "winreg.h"
36 #include "winternl.h"
37 #include "wine/unicode.h"
38
39 #include "rpc.h"
40 #include "rpcndr.h"
41
42 #include "wine/debug.h"
43
44 #include "rpc_binding.h"
45 #include "rpc_message.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(rpc);
48
49 LPSTR RPCRT4_strndupA(LPCSTR src, INT slen)
50 {
51 DWORD len;
52 LPSTR s;
53 if (!src) return NULL;
54 if (slen == -1) slen = strlen(src);
55 len = slen;
56 s = HeapAlloc(GetProcessHeap(), 0, len+1);
57 memcpy(s, src, len);
58 s[len] = 0;
59 return s;
60 }
61
62 LPSTR RPCRT4_strdupWtoA(LPWSTR src)
63 {
64 DWORD len;
65 LPSTR s;
66 if (!src) return NULL;
67 len = WideCharToMultiByte(CP_ACP, 0, src, -1, NULL, 0, NULL, NULL);
68 s = HeapAlloc(GetProcessHeap(), 0, len);
69 WideCharToMultiByte(CP_ACP, 0, src, -1, s, len, NULL, NULL);
70 return s;
71 }
72
73 LPWSTR RPCRT4_strdupAtoW(LPSTR src)
74 {
75 DWORD len;
76 LPWSTR s;
77 if (!src) return NULL;
78 len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
79 s = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
80 MultiByteToWideChar(CP_ACP, 0, src, -1, s, len);
81 return s;
82 }
83
84 LPWSTR RPCRT4_strndupW(LPWSTR src, INT slen)
85 {
86 DWORD len;
87 LPWSTR s;
88 if (!src) return NULL;
89 if (slen == -1) slen = strlenW(src);
90 len = slen;
91 s = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
92 memcpy(s, src, len*sizeof(WCHAR));
93 s[len] = 0;
94 return s;
95 }
96
97 void RPCRT4_strfree(LPSTR src)
98 {
99 HeapFree(GetProcessHeap(), 0, src);
100 }
101
102 RPC_STATUS RPCRT4_CreateConnection(RpcConnection** Connection, BOOL server, LPSTR Protseq, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions, RpcBinding* Binding)
103 {
104 RpcConnection* NewConnection;
105
106 NewConnection = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcConnection));
107 NewConnection->server = server;
108 NewConnection->Protseq = RPCRT4_strdupA(Protseq);
109 NewConnection->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
110 NewConnection->Endpoint = RPCRT4_strdupA(Endpoint);
111 NewConnection->Used = Binding;
112 NewConnection->MaxTransmissionSize = RPC_MAX_PACKET_SIZE;
113
114 TRACE("connection: %p\n", NewConnection);
115 *Connection = NewConnection;
116
117 return RPC_S_OK;
118 }
119
120 RPC_STATUS RPCRT4_DestroyConnection(RpcConnection* Connection)
121 {
122 TRACE("connection: %p\n", Connection);
123
124 RPCRT4_CloseConnection(Connection);
125 RPCRT4_strfree(Connection->Endpoint);
126 RPCRT4_strfree(Connection->NetworkAddr);
127 RPCRT4_strfree(Connection->Protseq);
128 HeapFree(GetProcessHeap(), 0, Connection);
129 return RPC_S_OK;
130 }
131
132 RPC_STATUS RPCRT4_OpenConnection(RpcConnection* Connection)
133 {
134 TRACE("(Connection == ^%p)\n", Connection);
135 if (!Connection->conn) {
136 if (Connection->server) { /* server */
137 /* protseq=ncalrpc: supposed to use NT LPC ports,
138 * but we'll implement it with named pipes for now */
139 if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
140 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
141 LPSTR pname;
142 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
143 strcat(strcpy(pname, prefix), Connection->Endpoint);
144 TRACE("listening on %s\n", pname);
145 Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
146 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_UNLIMITED_INSTANCES,
147 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
148 HeapFree(GetProcessHeap(), 0, pname);
149 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
150 Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
151 Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
152 if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) {
153 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
154 if (GetLastError() == ERROR_PIPE_CONNECTED) {
155 SetEvent(Connection->ovl[0].hEvent);
156 return RPC_S_OK;
157 } else if (GetLastError() == ERROR_IO_PENDING) {
158 return RPC_S_OK;
159 }
160 return RPC_S_SERVER_UNAVAILABLE;
161 }
162 }
163 /* protseq=ncacn_np: named pipes */
164 else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
165 static LPCSTR prefix = "\\\\.";
166 LPSTR pname;
167 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
168 strcat(strcpy(pname, prefix), Connection->Endpoint);
169 TRACE("listening on %s\n", pname);
170 Connection->conn = CreateNamedPipeA(pname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
171 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
172 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE, 5000, NULL);
173 HeapFree(GetProcessHeap(), 0, pname);
174 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
175 Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
176 Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
177 if (!ConnectNamedPipe(Connection->conn, &Connection->ovl[0])) {
178 if (GetLastError() == ERROR_PIPE_CONNECTED) {
179 SetEvent(Connection->ovl[0].hEvent);
180 return RPC_S_OK;
181 } else if (GetLastError() == ERROR_IO_PENDING) {
182 return RPC_S_OK;
183 }
184 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
185 return RPC_S_SERVER_UNAVAILABLE;
186 }
187 }
188 else {
189 ERR("protseq %s not supported\n", Connection->Protseq);
190 return RPC_S_PROTSEQ_NOT_SUPPORTED;
191 }
192 }
193 else { /* client */
194 /* protseq=ncalrpc: supposed to use NT LPC ports,
195 * but we'll implement it with named pipes for now */
196 if (strcmp(Connection->Protseq, "ncalrpc") == 0) {
197 static LPCSTR prefix = "\\\\.\\pipe\\lrpc\\";
198 LPSTR pname;
199 HANDLE conn;
200 DWORD err;
201 DWORD dwMode;
202
203 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
204 strcat(strcpy(pname, prefix), Connection->Endpoint);
205 TRACE("connecting to %s\n", pname);
206 while (TRUE) {
207 if (WaitNamedPipeA(pname, NMPWAIT_WAIT_FOREVER)) {
208 conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
209 OPEN_EXISTING, 0, 0);
210 if (conn != INVALID_HANDLE_VALUE) break;
211 err = GetLastError();
212 if (err == ERROR_PIPE_BUSY) continue;
213 TRACE("connection failed, error=%lx\n", err);
214 HeapFree(GetProcessHeap(), 0, pname);
215 return RPC_S_SERVER_TOO_BUSY;
216 } else {
217 err = GetLastError();
218 WARN("connection failed, error=%lx\n", err);
219 HeapFree(GetProcessHeap(), 0, pname);
220 return RPC_S_SERVER_UNAVAILABLE;
221 }
222 }
223
224 /* success */
225 HeapFree(GetProcessHeap(), 0, pname);
226 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
227 /* pipe is connected; change to message-read mode. */
228 dwMode = PIPE_READMODE_MESSAGE;
229 SetNamedPipeHandleState(conn, &dwMode, NULL, NULL);
230 Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
231 Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
232 Connection->conn = conn;
233 }
234 /* protseq=ncacn_np: named pipes */
235 else if (strcmp(Connection->Protseq, "ncacn_np") == 0) {
236 static LPCSTR prefix = "\\\\.";
237 LPSTR pname;
238 HANDLE conn;
239 DWORD err;
240 DWORD dwMode;
241
242 pname = HeapAlloc(GetProcessHeap(), 0, strlen(prefix) + strlen(Connection->Endpoint) + 1);
243 strcat(strcpy(pname, prefix), Connection->Endpoint);
244 TRACE("connecting to %s\n", pname);
245 conn = CreateFileA(pname, GENERIC_READ|GENERIC_WRITE, 0, NULL,
246 OPEN_EXISTING, 0, 0);
247 if (conn == INVALID_HANDLE_VALUE) {
248 err = GetLastError();
249 /* we don't need to handle ERROR_PIPE_BUSY here,
250 * the doc says that it is returned to the app */
251 WARN("connection failed, error=%lx\n", err);
252 HeapFree(GetProcessHeap(), 0, pname);
253 if (err == ERROR_PIPE_BUSY)
254 return RPC_S_SERVER_TOO_BUSY;
255 else
256 return RPC_S_SERVER_UNAVAILABLE;
257 }
258
259 /* success */
260 HeapFree(GetProcessHeap(), 0, pname);
261 memset(&Connection->ovl, 0, sizeof(Connection->ovl));
262 /* pipe is connected; change to message-read mode. */
263 dwMode = PIPE_READMODE_MESSAGE;
264 SetNamedPipeHandleState(conn, &dwMode, NULL, NULL);
265 Connection->ovl[0].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
266 Connection->ovl[1].hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
267 Connection->conn = conn;
268 } else {
269 ERR("protseq %s not supported\n", Connection->Protseq);
270 return RPC_S_PROTSEQ_NOT_SUPPORTED;
271 }
272 }
273 }
274 return RPC_S_OK;
275 }
276
277 RPC_STATUS RPCRT4_CloseConnection(RpcConnection* Connection)
278 {
279 TRACE("(Connection == ^%p)\n", Connection);
280 if (Connection->conn) {
281 FlushFileBuffers(Connection->conn);
282 CloseHandle(Connection->conn);
283 Connection->conn = 0;
284 }
285 if (Connection->ovl[0].hEvent) {
286 CloseHandle(Connection->ovl[0].hEvent);
287 Connection->ovl[0].hEvent = 0;
288 }
289 if (Connection->ovl[1].hEvent) {
290 CloseHandle(Connection->ovl[1].hEvent);
291 Connection->ovl[1].hEvent = 0;
292 }
293 return RPC_S_OK;
294 }
295
296 RPC_STATUS RPCRT4_SpawnConnection(RpcConnection** Connection, RpcConnection* OldConnection)
297 {
298 RpcConnection* NewConnection;
299 RPC_STATUS err = RPCRT4_CreateConnection(&NewConnection, OldConnection->server, OldConnection->Protseq,
300 OldConnection->NetworkAddr, OldConnection->Endpoint, NULL, NULL);
301 if (err == RPC_S_OK) {
302 /* because of the way named pipes work, we'll transfer the connected pipe
303 * to the child, then reopen the server binding to continue listening */
304 NewConnection->conn = OldConnection->conn;
305 NewConnection->ovl[0] = OldConnection->ovl[0];
306 NewConnection->ovl[1] = OldConnection->ovl[1];
307 OldConnection->conn = 0;
308 memset(&OldConnection->ovl, 0, sizeof(OldConnection->ovl));
309 *Connection = NewConnection;
310 RPCRT4_OpenConnection(OldConnection);
311 }
312 return err;
313 }
314
315 static RPC_STATUS RPCRT4_AllocBinding(RpcBinding** Binding, BOOL server)
316 {
317 RpcBinding* NewBinding;
318
319 NewBinding = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RpcBinding));
320 NewBinding->refs = 1;
321 NewBinding->server = server;
322
323 *Binding = NewBinding;
324
325 return RPC_S_OK;
326 }
327
328 RPC_STATUS RPCRT4_CreateBindingA(RpcBinding** Binding, BOOL server, LPSTR Protseq)
329 {
330 RpcBinding* NewBinding;
331
332 RPCRT4_AllocBinding(&NewBinding, server);
333 NewBinding->Protseq = RPCRT4_strdupA(Protseq);
334
335 TRACE("binding: %p\n", NewBinding);
336 *Binding = NewBinding;
337
338 return RPC_S_OK;
339 }
340
341 RPC_STATUS RPCRT4_CreateBindingW(RpcBinding** Binding, BOOL server, LPWSTR Protseq)
342 {
343 RpcBinding* NewBinding;
344
345 RPCRT4_AllocBinding(&NewBinding, server);
346 NewBinding->Protseq = RPCRT4_strdupWtoA(Protseq);
347
348 TRACE("binding: %p\n", NewBinding);
349 *Binding = NewBinding;
350
351 return RPC_S_OK;
352 }
353
354 RPC_STATUS RPCRT4_CompleteBindingA(RpcBinding* Binding, LPSTR NetworkAddr, LPSTR Endpoint, LPSTR NetworkOptions)
355 {
356 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
357 debugstr_a(NetworkAddr), debugstr_a(Endpoint), debugstr_a(NetworkOptions));
358
359 RPCRT4_strfree(Binding->NetworkAddr);
360 Binding->NetworkAddr = RPCRT4_strdupA(NetworkAddr);
361 RPCRT4_strfree(Binding->Endpoint);
362 if (Endpoint) {
363 Binding->Endpoint = RPCRT4_strdupA(Endpoint);
364 } else {
365 Binding->Endpoint = RPCRT4_strdupA("");
366 }
367 if (!Binding->Endpoint) ERR("out of memory?\n");
368
369 return RPC_S_OK;
370 }
371
372 RPC_STATUS RPCRT4_CompleteBindingW(RpcBinding* Binding, LPWSTR NetworkAddr, LPWSTR Endpoint, LPWSTR NetworkOptions)
373 {
374 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding,
375 debugstr_w(NetworkAddr), debugstr_w(Endpoint), debugstr_w(NetworkOptions));
376
377 RPCRT4_strfree(Binding->NetworkAddr);
378 Binding->NetworkAddr = RPCRT4_strdupWtoA(NetworkAddr);
379 RPCRT4_strfree(Binding->Endpoint);
380 if (Endpoint) {
381 Binding->Endpoint = RPCRT4_strdupWtoA(Endpoint);
382 } else {
383 Binding->Endpoint = RPCRT4_strdupA("");
384 }
385 if (!Binding->Endpoint) ERR("out of memory?\n");
386
387 return RPC_S_OK;
388 }
389
390 RPC_STATUS RPCRT4_ResolveBinding(RpcBinding* Binding, LPSTR Endpoint)
391 {
392 TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding, Endpoint);
393
394 RPCRT4_strfree(Binding->Endpoint);
395 Binding->Endpoint = RPCRT4_strdupA(Endpoint);
396
397 return RPC_S_OK;
398 }
399
400 RPC_STATUS RPCRT4_SetBindingObject(RpcBinding* Binding, UUID* ObjectUuid)
401 {
402 TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding, debugstr_guid(ObjectUuid));
403 if (ObjectUuid) memcpy(&Binding->ObjectUuid, ObjectUuid, sizeof(UUID));
404 else UuidCreateNil(&Binding->ObjectUuid);
405 return RPC_S_OK;
406 }
407
408 RPC_STATUS RPCRT4_MakeBinding(RpcBinding** Binding, RpcConnection* Connection)
409 {
410 RpcBinding* NewBinding;
411 TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding, Connection);
412
413 RPCRT4_AllocBinding(&NewBinding, Connection->server);
414 NewBinding->Protseq = RPCRT4_strdupA(Connection->Protseq);
415 NewBinding->NetworkAddr = RPCRT4_strdupA(Connection->NetworkAddr);
416 NewBinding->Endpoint = RPCRT4_strdupA(Connection->Endpoint);
417 NewBinding->FromConn = Connection;
418
419 TRACE("binding: %p\n", NewBinding);
420 *Binding = NewBinding;
421
422 return RPC_S_OK;
423 }
424
425 RPC_STATUS RPCRT4_ExportBinding(RpcBinding** Binding, RpcBinding* OldBinding)
426 {
427 InterlockedIncrement(&OldBinding->refs);
428 *Binding = OldBinding;
429 return RPC_S_OK;
430 }
431
432 RPC_STATUS RPCRT4_DestroyBinding(RpcBinding* Binding)
433 {
434 if (InterlockedDecrement(&Binding->refs))
435 return RPC_S_OK;
436
437 TRACE("binding: %p\n", Binding);
438 /* FIXME: release connections */
439 RPCRT4_strfree(Binding->Endpoint);
440 RPCRT4_strfree(Binding->NetworkAddr);
441 RPCRT4_strfree(Binding->Protseq);
442 HeapFree(GetProcessHeap(), 0, Binding);
443 return RPC_S_OK;
444 }
445
446 RPC_STATUS RPCRT4_OpenBinding(RpcBinding* Binding, RpcConnection** Connection,
447 PRPC_SYNTAX_IDENTIFIER TransferSyntax,
448 PRPC_SYNTAX_IDENTIFIER InterfaceId)
449 {
450 RpcConnection* NewConnection;
451 RPC_STATUS status;
452
453 TRACE("(Binding == ^%p)\n", Binding);
454
455 /* if we try to bind a new interface and the connection is already opened,
456 * close the current connection and create a new with the new binding. */
457 if (!Binding->server && Binding->FromConn &&
458 memcmp(&Binding->FromConn->ActiveInterface, InterfaceId,
459 sizeof(RPC_SYNTAX_IDENTIFIER))) {
460
461 TRACE("releasing pre-existing connection\n");
462 RPCRT4_DestroyConnection(Binding->FromConn);
463 Binding->FromConn = NULL;
464 } else {
465 /* we already have a connection with acceptable binding, so use it */
466 if (Binding->FromConn) {
467 *Connection = Binding->FromConn;
468 return RPC_S_OK;
469 }
470 }
471
472 /* create a new connection */
473 RPCRT4_CreateConnection(&NewConnection, Binding->server, Binding->Protseq, Binding->NetworkAddr, Binding->Endpoint, NULL, Binding);
474 *Connection = NewConnection;
475 status = RPCRT4_OpenConnection(NewConnection);
476 if (status != RPC_S_OK) {
477 return status;
478 }
479
480 /* we need to send a binding packet if we are client. */
481 if (!(*Connection)->server) {
482 RpcPktHdr *hdr;
483 DWORD count;
484 BYTE *response;
485 RpcPktHdr *response_hdr;
486
487 TRACE("sending bind request to server\n");
488
489 hdr = RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION,
490 RPC_MAX_PACKET_SIZE, RPC_MAX_PACKET_SIZE,
491 InterfaceId, TransferSyntax);
492
493 status = RPCRT4_Send(*Connection, hdr, NULL, 0);
494 if (status != RPC_S_OK) {
495 RPCRT4_DestroyConnection(*Connection);
496 return status;
497 }
498
499 response = HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE);
500 if (response == NULL) {
501 WARN("Can't allocate memory for binding response\n");
502 RPCRT4_DestroyConnection(*Connection);
503 return E_OUTOFMEMORY;
504 }
505
506 /* get a reply */
507 if (!ReadFile(NewConnection->conn, response, RPC_MAX_PACKET_SIZE, &count, NULL)) {
508 WARN("ReadFile failed with error %ld\n", GetLastError());
509 RPCRT4_DestroyConnection(*Connection);
510 return RPC_S_PROTOCOL_ERROR;
511 }
512
513 if (count < sizeof(response_hdr->common)) {
514 WARN("received invalid header\n");
515 RPCRT4_DestroyConnection(*Connection);
516 return RPC_S_PROTOCOL_ERROR;
517 }
518
519 response_hdr = (RpcPktHdr*)response;
520
521 if (response_hdr->common.rpc_ver != RPC_VER_MAJOR ||
522 response_hdr->common.rpc_ver_minor != RPC_VER_MINOR ||
523 response_hdr->common.ptype != PKT_BIND_ACK) {
524 WARN("invalid protocol version or rejection packet\n");
525 RPCRT4_DestroyConnection(*Connection);
526 return RPC_S_PROTOCOL_ERROR;
527 }
528
529 if (response_hdr->bind_ack.max_tsize < RPC_MIN_PACKET_SIZE) {
530 WARN("server doesn't allow large enough packets\n");
531 RPCRT4_DestroyConnection(*Connection);
532 return RPC_S_PROTOCOL_ERROR;
533 }
534
535 /* FIXME: do more checks? */
536
537 (*Connection)->MaxTransmissionSize = response_hdr->bind_ack.max_tsize;
538 (*Connection)->ActiveInterface = *InterfaceId;
539 }
540
541 return RPC_S_OK;
542 }
543
544 RPC_STATUS RPCRT4_CloseBinding(RpcBinding* Binding, RpcConnection* Connection)
545 {
546 TRACE("(Binding == ^%p)\n", Binding);
547 if (!Connection) return RPC_S_OK;
548 if (Binding->FromConn == Connection) return RPC_S_OK;
549 return RPCRT4_DestroyConnection(Connection);
550 }
551
552 /* utility functions for string composing and parsing */
553 static unsigned RPCRT4_strcopyA(LPSTR data, LPCSTR src)
554 {
555 unsigned len = strlen(src);
556 memcpy(data, src, len*sizeof(CHAR));
557 return len;
558 }
559
560 static unsigned RPCRT4_strcopyW(LPWSTR data, LPCWSTR src)
561 {
562 unsigned len = strlenW(src);
563 memcpy(data, src, len*sizeof(WCHAR));
564 return len;
565 }
566
567 static LPSTR RPCRT4_strconcatA(LPSTR dst, LPCSTR src)
568 {
569 DWORD len = strlen(dst), slen = strlen(src);
570 LPSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(CHAR));
571 if (!ndst)
572 {
573 HeapFree(GetProcessHeap(), 0, dst);
574 return NULL;
575 }
576 ndst[len] = ',';
577 memcpy(ndst+len+1, src, slen+1);
578 return ndst;
579 }
580
581 static LPWSTR RPCRT4_strconcatW(LPWSTR dst, LPCWSTR src)
582 {
583 DWORD len = strlenW(dst), slen = strlenW(src);
584 LPWSTR ndst = HeapReAlloc(GetProcessHeap(), 0, dst, (len+slen+2)*sizeof(WCHAR));
585 if (!ndst)
586 {
587 HeapFree(GetProcessHeap(), 0, dst);
588 return NULL;
589 }
590 ndst[len] = ',';
591 memcpy(ndst+len+1, src, (slen+1)*sizeof(WCHAR));
592 return ndst;
593 }
594
595
596 /***********************************************************************
597 * RpcStringBindingComposeA (RPCRT4.@)
598 */
599 RPC_STATUS WINAPI RpcStringBindingComposeA(unsigned char *ObjUuid, unsigned char *Protseq,
600 unsigned char *NetworkAddr, unsigned char *Endpoint,
601 unsigned char *Options, unsigned char** StringBinding )
602 {
603 DWORD len = 1;
604 LPSTR data;
605
606 TRACE( "(%s,%s,%s,%s,%s,%p)\n",
607 debugstr_a( (char*)ObjUuid ), debugstr_a( (char*)Protseq ),
608 debugstr_a( (char*)NetworkAddr ), debugstr_a( (char*)Endpoint ),
609 debugstr_a( (char*)Options ), StringBinding );
610
611 if (ObjUuid && *ObjUuid) len += strlen((char*)ObjUuid) + 1;
612 if (Protseq && *Protseq) len += strlen((char*)Protseq) + 1;
613 if (NetworkAddr && *NetworkAddr) len += strlen((char*)NetworkAddr);
614 if (Endpoint && *Endpoint) len += strlen((char*)Endpoint) + 2;
615 if (Options && *Options) len += strlen((char*)Options) + 2;
616
617 data = HeapAlloc(GetProcessHeap(), 0, len);
618 *StringBinding = (unsigned char*)data;
619
620 if (ObjUuid && *ObjUuid) {
621 data += RPCRT4_strcopyA(data, (char*)ObjUuid);
622 *data++ = '@';
623 }
624 if (Protseq && *Protseq) {
625 data += RPCRT4_strcopyA(data, (char*)Protseq);
626 *data++ = ':';
627 }
628 if (NetworkAddr && *NetworkAddr)
629 data += RPCRT4_strcopyA(data, (char*)NetworkAddr);
630
631 if ((Endpoint && *Endpoint) ||
632 (Options && *Options)) {
633 *data++ = '[';
634 if (Endpoint && *Endpoint) {
635 data += RPCRT4_strcopyA(data, (char*)Endpoint);
636 if (Options && *Options) *data++ = ',';
637 }
638 if (Options && *Options) {
639 data += RPCRT4_strcopyA(data, (char*)Options);
640 }
641 *data++ = ']';
642 }
643 *data = 0;
644
645 return RPC_S_OK;
646 }
647
648 /***********************************************************************
649 * RpcStringBindingComposeW (RPCRT4.@)
650 */
651 RPC_STATUS WINAPI RpcStringBindingComposeW( LPWSTR ObjUuid, LPWSTR Protseq,
652 LPWSTR NetworkAddr, LPWSTR Endpoint,
653 LPWSTR Options, LPWSTR* StringBinding )
654 {
655 DWORD len = 1;
656 LPWSTR data;
657
658 TRACE("(%s,%s,%s,%s,%s,%p)\n",
659 debugstr_w( ObjUuid ), debugstr_w( Protseq ),
660 debugstr_w( NetworkAddr ), debugstr_w( Endpoint ),
661 debugstr_w( Options ), StringBinding);
662
663 if (ObjUuid && *ObjUuid) len += strlenW(ObjUuid) + 1;
664 if (Protseq && *Protseq) len += strlenW(Protseq) + 1;
665 if (NetworkAddr && *NetworkAddr) len += strlenW(NetworkAddr);
666 if (Endpoint && *Endpoint) len += strlenW(Endpoint) + 2;
667 if (Options && *Options) len += strlenW(Options) + 2;
668
669 data = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
670 *StringBinding = data;
671
672 if (ObjUuid && *ObjUuid) {
673 data += RPCRT4_strcopyW(data, ObjUuid);
674 *data++ = '@';
675 }
676 if (Protseq && *Protseq) {
677 data += RPCRT4_strcopyW(data, Protseq);
678 *data++ = ':';
679 }
680 if (NetworkAddr && *NetworkAddr) {
681 data += RPCRT4_strcopyW(data, NetworkAddr);
682 }
683 if ((Endpoint && *Endpoint) ||
684 (Options && *Options)) {
685 *data++ = '[';
686 if (Endpoint && *Endpoint) {
687 data += RPCRT4_strcopyW(data, Endpoint);
688 if (Options && *Options) *data++ = ',';
689 }
690 if (Options && *Options) {
691 data += RPCRT4_strcopyW(data, Options);
692 }
693 *data++ = ']';
694 }
695 *data = 0;
696
697 return RPC_S_OK;
698 }
699
700
701 /***********************************************************************
702 * RpcStringBindingParseA (RPCRT4.@)
703 */
704 RPC_STATUS WINAPI RpcStringBindingParseA( unsigned char *StringBinding, unsigned char **ObjUuid,
705 unsigned char **Protseq, unsigned char **NetworkAddr,
706 unsigned char **Endpoint, unsigned char **Options)
707 {
708 CHAR *data, *next;
709 static const char ep_opt[] = "endpoint=";
710
711 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a((char*)StringBinding),
712 ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
713
714 if (ObjUuid) *ObjUuid = NULL;
715 if (Protseq) *Protseq = NULL;
716 if (NetworkAddr) *NetworkAddr = NULL;
717 if (Endpoint) *Endpoint = NULL;
718 if (Options) *Options = NULL;
719
720 data = (char*) StringBinding;
721
722 next = strchr(data, '@');
723 if (next) {
724 if (ObjUuid) *ObjUuid = (unsigned char*)RPCRT4_strndupA(data, next - data);
725 data = next+1;
726 }
727
728 next = strchr(data, ':');
729 if (next) {
730 if (Protseq) *Protseq = (unsigned char*)RPCRT4_strndupA(data, next - data);
731 data = next+1;
732 }
733
734 next = strchr(data, '[');
735 if (next) {
736 CHAR *close, *opt;
737
738 if (NetworkAddr) *NetworkAddr = (unsigned char*)RPCRT4_strndupA(data, next - data);
739 data = next+1;
740 close = strchr(data, ']');
741 if (!close) goto fail;
742
743 /* tokenize options */
744 while (data < close) {
745 next = strchr(data, ',');
746 if (!next || next > close) next = close;
747 /* FIXME: this is kind of inefficient */
748 opt = RPCRT4_strndupA(data, next - data);
749 data = next+1;
750
751 /* parse option */
752 next = strchr(opt, '=');
753 if (!next) {
754 /* not an option, must be an endpoint */
755 if (*Endpoint) goto fail;
756 *Endpoint = (unsigned char*) opt;
757 } else {
758 if (strncmp(opt, ep_opt, strlen(ep_opt)) == 0) {
759 /* endpoint option */
760 if (*Endpoint) goto fail;
761 *Endpoint = (unsigned char*) RPCRT4_strdupA(next+1);
762 HeapFree(GetProcessHeap(), 0, opt);
763 } else {
764 /* network option */
765 if (*Options) {
766 /* FIXME: this is kind of inefficient */
767 *Options = (unsigned char*) RPCRT4_strconcatA( (char*)*Options, opt);
768 HeapFree(GetProcessHeap(), 0, opt);
769 } else
770 *Options = (unsigned char*) opt;
771 }
772 }
773 }
774
775 data = close+1;
776 if (*data) goto fail;
777 }
778 else if (NetworkAddr)
779 *NetworkAddr = (unsigned char*)RPCRT4_strdupA(data);
780
781 return RPC_S_OK;
782
783 fail:
784 if (ObjUuid) RpcStringFreeA((unsigned char**)ObjUuid);
785 if (Protseq) RpcStringFreeA((unsigned char**)Protseq);
786 if (NetworkAddr) RpcStringFreeA((unsigned char**)NetworkAddr);
787 if (Endpoint) RpcStringFreeA((unsigned char**)Endpoint);
788 if (Options) RpcStringFreeA((unsigned char**)Options);
789 return RPC_S_INVALID_STRING_BINDING;
790 }
791
792 /***********************************************************************
793 * RpcStringBindingParseW (RPCRT4.@)
794 */
795 RPC_STATUS WINAPI RpcStringBindingParseW( LPWSTR StringBinding, LPWSTR *ObjUuid,
796 LPWSTR *Protseq, LPWSTR *NetworkAddr,
797 LPWSTR *Endpoint, LPWSTR *Options)
798 {
799 WCHAR *data, *next;
800 static const WCHAR ep_opt[] = {'e','n','d','p','o','i','n','t','=',0};
801
802 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding),
803 ObjUuid, Protseq, NetworkAddr, Endpoint, Options);
804
805 if (ObjUuid) *ObjUuid = NULL;
806 if (Protseq) *Protseq = NULL;
807 if (NetworkAddr) *NetworkAddr = NULL;
808 if (Endpoint) *Endpoint = NULL;
809 if (Options) *Options = NULL;
810
811 data = StringBinding;
812
813 next = strchrW(data, '@');
814 if (next) {
815 if (ObjUuid) *ObjUuid = RPCRT4_strndupW(data, next - data);
816 data = next+1;
817 }
818
819 next = strchrW(data, ':');
820 if (next) {
821 if (Protseq) *Protseq = RPCRT4_strndupW(data, next - data);
822 data = next+1;
823 }
824
825 next = strchrW(data, '[');
826 if (next) {
827 WCHAR *close, *opt;
828
829 if (NetworkAddr) *NetworkAddr = RPCRT4_strndupW(data, next - data);
830 data = next+1;
831 close = strchrW(data, ']');
832 if (!close) goto fail;
833
834 /* tokenize options */
835 while (data < close) {
836 next = strchrW(data, ',');
837 if (!next || next > close) next = close;
838 /* FIXME: this is kind of inefficient */
839 opt = RPCRT4_strndupW(data, next - data);
840 data = next+1;
841
842 /* parse option */
843 next = strchrW(opt, '=');
844 if (!next) {
845 /* not an option, must be an endpoint */
846 if (*Endpoint) goto fail;
847 *Endpoint = opt;
848 } else {
849 if (strncmpW(opt, ep_opt, strlenW(ep_opt)) == 0) {
850 /* endpoint option */
851 if (*Endpoint) goto fail;
852 *Endpoint = RPCRT4_strdupW(next+1);
853 HeapFree(GetProcessHeap(), 0, opt);
854 } else {
855 /* network option */
856 if (*Options) {
857 /* FIXME: this is kind of inefficient */
858 *Options = RPCRT4_strconcatW(*Options, opt);
859 HeapFree(GetProcessHeap(), 0, opt);
860 } else
861 *Options = opt;
862 }
863 }
864 }
865
866 data = close+1;
867 if (*data) goto fail;
868 } else if (NetworkAddr)
869 *NetworkAddr = RPCRT4_strdupW(data);
870
871 return RPC_S_OK;
872
873 fail:
874 if (ObjUuid) RpcStringFreeW(ObjUuid);
875 if (Protseq) RpcStringFreeW(Protseq);
876 if (NetworkAddr) RpcStringFreeW(NetworkAddr);
877 if (Endpoint) RpcStringFreeW(Endpoint);
878 if (Options) RpcStringFreeW(Options);
879 return RPC_S_INVALID_STRING_BINDING;
880 }
881
882 /***********************************************************************
883 * RpcBindingFree (RPCRT4.@)
884 */
885 RPC_STATUS WINAPI RpcBindingFree( RPC_BINDING_HANDLE* Binding )
886 {
887 RPC_STATUS status;
888 TRACE("(%p) = %p\n", Binding, *Binding);
889 status = RPCRT4_DestroyBinding(*Binding);
890 if (status == RPC_S_OK) *Binding = 0;
891 return status;
892 }
893
894 /***********************************************************************
895 * RpcBindingVectorFree (RPCRT4.@)
896 */
897 RPC_STATUS WINAPI RpcBindingVectorFree( RPC_BINDING_VECTOR** BindingVector )
898 {
899 RPC_STATUS status;
900 unsigned long c;
901
902 TRACE("(%p)\n", BindingVector);
903 for (c=0; c<(*BindingVector)->Count; c++) {
904 status = RpcBindingFree(&(*BindingVector)->BindingH[c]);
905 }
906 HeapFree(GetProcessHeap(), 0, *BindingVector);
907 *BindingVector = NULL;
908 return RPC_S_OK;
909 }
910
911 /***********************************************************************
912 * RpcBindingInqObject (RPCRT4.@)
913 */
914 RPC_STATUS WINAPI RpcBindingInqObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
915 {
916 RpcBinding* bind = (RpcBinding*)Binding;
917
918 TRACE("(%p,%p) = %s\n", Binding, ObjectUuid, debugstr_guid(&bind->ObjectUuid));
919 memcpy(ObjectUuid, &bind->ObjectUuid, sizeof(UUID));
920 return RPC_S_OK;
921 }
922
923 /***********************************************************************
924 * RpcBindingSetObject (RPCRT4.@)
925 */
926 RPC_STATUS WINAPI RpcBindingSetObject( RPC_BINDING_HANDLE Binding, UUID* ObjectUuid )
927 {
928 RpcBinding* bind = (RpcBinding*)Binding;
929
930 TRACE("(%p,%s)\n", Binding, debugstr_guid(ObjectUuid));
931 if (bind->server) return RPC_S_WRONG_KIND_OF_BINDING;
932 return RPCRT4_SetBindingObject(Binding, ObjectUuid);
933 }
934
935 /***********************************************************************
936 * RpcBindingFromStringBindingA (RPCRT4.@)
937 */
938 RPC_STATUS WINAPI RpcBindingFromStringBindingA( unsigned char *StringBinding, RPC_BINDING_HANDLE* Binding )
939 {
940 RPC_STATUS ret;
941 RpcBinding* bind = NULL;
942 unsigned char *ObjectUuid, *Protseq, *NetworkAddr, *Endpoint, *Options;
943 UUID Uuid;
944
945 TRACE("(%s,%p)\n", debugstr_a((char*)StringBinding), Binding);
946
947 ret = RpcStringBindingParseA(StringBinding, &ObjectUuid, &Protseq,
948 &NetworkAddr, &Endpoint, &Options);
949 if (ret != RPC_S_OK) return ret;
950
951 ret = UuidFromStringA(ObjectUuid, &Uuid);
952
953 if (ret == RPC_S_OK)
954 ret = RPCRT4_CreateBindingA(&bind, FALSE, (char*)Protseq);
955 if (ret == RPC_S_OK)
956 ret = RPCRT4_SetBindingObject(bind, &Uuid);
957 if (ret == RPC_S_OK)
958 ret = RPCRT4_CompleteBindingA(bind, (char*)NetworkAddr, (char*)Endpoint, (char*)Options);
959
960 RpcStringFreeA((unsigned char**)&Options);
961 RpcStringFreeA((unsigned char**)&Endpoint);
962 RpcStringFreeA((unsigned char**)&NetworkAddr);
963 RpcStringFreeA((unsigned char**)&Protseq);
964 RpcStringFreeA((unsigned char**)&ObjectUuid);
965
966 if (ret == RPC_S_OK)
967 *Binding = (RPC_BINDING_HANDLE)bind;
968 else
969 RPCRT4_DestroyBinding(bind);
970
971 return ret;
972 }
973
974 /***********************************************************************
975 * RpcBindingFromStringBindingW (RPCRT4.@)
976 */
977 RPC_STATUS WINAPI RpcBindingFromStringBindingW( LPWSTR StringBinding, RPC_BINDING_HANDLE* Binding )
978 {
979 RPC_STATUS ret;
980 RpcBinding* bind = NULL;
981 LPWSTR ObjectUuid, Protseq, NetworkAddr, Endpoint, Options;
982 UUID Uuid;
983
984 TRACE("(%s,%p)\n", debugstr_w(StringBinding), Binding);
985
986 ret = RpcStringBindingParseW(StringBinding, &ObjectUuid, &Protseq,
987 &NetworkAddr, &Endpoint, &Options);
988 if (ret != RPC_S_OK) return ret;
989
990 ret = UuidFromStringW(ObjectUuid, &Uuid);
991
992 if (ret == RPC_S_OK)
993 ret = RPCRT4_CreateBindingW(&bind, FALSE, Protseq);
994 if (ret == RPC_S_OK)
995 ret = RPCRT4_SetBindingObject(bind, &Uuid);
996 if (ret == RPC_S_OK)
997 ret = RPCRT4_CompleteBindingW(bind, NetworkAddr, Endpoint, Options);
998
999 RpcStringFreeW(&Options);
1000 RpcStringFreeW(&Endpoint);
1001 RpcStringFreeW(&NetworkAddr);
1002 RpcStringFreeW(&Protseq);
1003 RpcStringFreeW(&ObjectUuid);
1004
1005 if (ret == RPC_S_OK)
1006 *Binding = (RPC_BINDING_HANDLE)bind;
1007 else
1008 RPCRT4_DestroyBinding(bind);
1009
1010 return ret;
1011 }
1012
1013 /***********************************************************************
1014 * RpcBindingToStringBindingA (RPCRT4.@)
1015 */
1016 RPC_STATUS WINAPI RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding, unsigned char** StringBinding )
1017 {
1018 RPC_STATUS ret;
1019 RpcBinding* bind = (RpcBinding*)Binding;
1020 LPSTR ObjectUuid;
1021
1022 TRACE("(%p,%p)\n", Binding, StringBinding);
1023
1024 ret = UuidToStringA(&bind->ObjectUuid, (unsigned char**)&ObjectUuid);
1025 if (ret != RPC_S_OK) return ret;
1026
1027 ret = RpcStringBindingComposeA((unsigned char*) ObjectUuid, (unsigned char*)bind->Protseq, (unsigned char*) bind->NetworkAddr,
1028 (unsigned char*) bind->Endpoint, NULL, StringBinding);
1029
1030 RpcStringFreeA((unsigned char**)&ObjectUuid);
1031
1032 return ret;
1033 }
1034
1035 /***********************************************************************
1036 * RpcBindingToStringBindingW (RPCRT4.@)
1037 */
1038 RPC_STATUS WINAPI RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding, unsigned short** StringBinding )
1039 {
1040 RPC_STATUS ret;
1041 unsigned char *str = NULL;
1042 TRACE("(%p,%p)\n", Binding, StringBinding);
1043 ret = RpcBindingToStringBindingA(Binding, &str);
1044 *StringBinding = RPCRT4_strdupAtoW((char*)str);
1045 RpcStringFreeA((unsigned char**)&str);
1046 return ret;
1047 }
1048
1049 /***********************************************************************
1050 * I_RpcBindingSetAsync (RPCRT4.@)
1051 * NOTES
1052 * Exists in win9x and winNT, but with different number of arguments
1053 * (9x version has 3 arguments, NT has 2).
1054 */
1055 RPC_STATUS WINAPI I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding, RPC_BLOCKING_FN BlockingFn)
1056 {
1057 RpcBinding* bind = (RpcBinding*)Binding;
1058
1059 TRACE( "(%p,%p): stub\n", Binding, BlockingFn );
1060
1061 bind->BlockingFn = BlockingFn;
1062
1063 return RPC_S_OK;
1064 }
1065
1066 /***********************************************************************
1067 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1068 */
1069 RPC_STATUS WINAPI RpcNetworkIsProtseqValidA(unsigned char *protseq) {
1070 UNICODE_STRING protseqW;
1071
1072 if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */
1073
1074 if (RtlCreateUnicodeStringFromAsciiz(&protseqW, (char*)protseq)) {
1075 RPC_STATUS ret = RpcNetworkIsProtseqValidW(protseqW.Buffer);
1076 RtlFreeUnicodeString(&protseqW);
1077 return ret;
1078 } else return RPC_S_OUT_OF_MEMORY;
1079 }
1080
1081 /***********************************************************************
1082 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1083 *
1084 * Checks if the given protocol sequence is known by the RPC system.
1085 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1086 *
1087 * We currently support:
1088 * ncalrpc local-only rpc over LPC (LPC is not really used)
1089 * ncacn_np rpc over named pipes
1090 */
1091 RPC_STATUS WINAPI RpcNetworkIsProtseqValidW(LPWSTR protseq) {
1092 static const WCHAR protseqsW[][15] = {
1093 {'n','c','a','l','r','p','c',0},
1094 {'n','c','a','c','n','_','n','p',0}
1095 };
1096 static const int count = sizeof(protseqsW) / sizeof(protseqsW[0]);
1097 int i;
1098
1099 if (!protseq) return RPC_S_INVALID_RPC_PROTSEQ; /* ? */
1100
1101 for (i = 0; i < count; i++) {
1102 if (!strcmpW(protseq, protseqsW[i])) return RPC_S_OK;
1103 }
1104
1105 FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq));
1106 return RPC_S_PROTSEQ_NOT_SUPPORTED;
1107 }
1108
1109 /***********************************************************************
1110 * RpcImpersonateClient (RPCRT4.@)
1111 *
1112 * Impersonates the client connected via a binding handle so that security
1113 * checks are done in the context of the client.
1114 *
1115 * PARAMS
1116 * BindingHandle [I] Handle to the binding to the client.
1117 *
1118 * RETURNS
1119 * Success: RPS_S_OK.
1120 * Failure: RPC_STATUS value.
1121 *
1122 * NOTES
1123 *
1124 * If BindingHandle is NULL then the function impersonates the client
1125 * connected to the binding handle of the current thread.
1126 */
1127 RPC_STATUS WINAPI RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle)
1128 {
1129 FIXME("(%p): stub\n", BindingHandle);
1130 return RPC_S_OK;
1131 }
1132
1133 /***********************************************************************
1134 * RpcRevertToSelfEx (RPCRT4.@)
1135 *
1136 * Stops impersonating the client connected to the binding handle so that security
1137 * checks are no longer done in the context of the client.
1138 *
1139 * PARAMS
1140 * BindingHandle [I] Handle to the binding to the client.
1141 *
1142 * RETURNS
1143 * Success: RPS_S_OK.
1144 * Failure: RPC_STATUS value.
1145 *
1146 * NOTES
1147 *
1148 * If BindingHandle is NULL then the function stops impersonating the client
1149 * connected to the binding handle of the current thread.
1150 */
1151 RPC_STATUS WINAPI RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle)
1152 {
1153 FIXME("(%p): stub\n", BindingHandle);
1154 return RPC_S_OK;
1155 }