4 * Copyright 2001 Ove Kåven, TransGaming Technologies
5 * Copyright 2003 Mike Hearn
6 * Copyright 2004 Filip Navara
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.
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.
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
37 #include "wine/unicode.h"
42 #include "wine/debug.h"
44 #include "rpc_binding.h"
45 #include "rpc_message.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(rpc
);
49 LPSTR
RPCRT4_strndupA(LPCSTR src
, INT slen
)
53 if (!src
) return NULL
;
54 if (slen
== -1) slen
= strlen(src
);
56 s
= HeapAlloc(GetProcessHeap(), 0, len
+1);
62 LPSTR
RPCRT4_strdupWtoA(LPWSTR src
)
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
);
73 LPWSTR
RPCRT4_strdupAtoW(LPSTR src
)
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
);
84 LPWSTR
RPCRT4_strndupW(LPWSTR src
, INT slen
)
88 if (!src
) return NULL
;
89 if (slen
== -1) slen
= strlenW(src
);
91 s
= HeapAlloc(GetProcessHeap(), 0, (len
+1)*sizeof(WCHAR
));
92 memcpy(s
, src
, len
*sizeof(WCHAR
));
97 void RPCRT4_strfree(LPSTR src
)
99 HeapFree(GetProcessHeap(), 0, src
);
102 RPC_STATUS
RPCRT4_CreateConnection(RpcConnection
** Connection
, BOOL server
, LPSTR Protseq
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
, RpcBinding
* Binding
)
104 RpcConnection
* NewConnection
;
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
;
114 TRACE("connection: %p\n", NewConnection
);
115 *Connection
= NewConnection
;
120 RPC_STATUS
RPCRT4_DestroyConnection(RpcConnection
* Connection
)
122 TRACE("connection: %p\n", Connection
);
124 RPCRT4_CloseConnection(Connection
);
125 RPCRT4_strfree(Connection
->Endpoint
);
126 RPCRT4_strfree(Connection
->NetworkAddr
);
127 RPCRT4_strfree(Connection
->Protseq
);
128 HeapFree(GetProcessHeap(), 0, Connection
);
132 RPC_STATUS
RPCRT4_OpenConnection(RpcConnection
* Connection
)
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\\";
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
,
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
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
151 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
)) {
152 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
153 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
154 SetEvent(Connection
->ovl
.hEvent
);
156 } else if (GetLastError() == ERROR_IO_PENDING
) {
159 return RPC_S_SERVER_UNAVAILABLE
;
162 /* protseq=ncacn_np: named pipes */
163 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
164 static LPCSTR prefix
= "\\\\.";
166 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
167 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
168 TRACE("listening on %s\n", pname
);
169 Connection
->conn
= CreateNamedPipeA(pname
, PIPE_ACCESS_DUPLEX
,
170 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
, PIPE_UNLIMITED_INSTANCES
,
171 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
, 5000, NULL
);
172 HeapFree(GetProcessHeap(), 0, pname
);
173 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
174 Connection
->ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
175 if (!ConnectNamedPipe(Connection
->conn
, &Connection
->ovl
)) {
176 if (GetLastError() == ERROR_PIPE_CONNECTED
) {
177 SetEvent(Connection
->ovl
.hEvent
);
179 } else if (GetLastError() == ERROR_IO_PENDING
) {
182 WARN("Couldn't ConnectNamedPipe (error was %ld)\n", GetLastError());
183 return RPC_S_SERVER_UNAVAILABLE
;
187 ERR("protseq %s not supported\n", Connection
->Protseq
);
188 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
192 /* protseq=ncalrpc: supposed to use NT LPC ports,
193 * but we'll implement it with named pipes for now */
194 if (strcmp(Connection
->Protseq
, "ncalrpc") == 0) {
195 static LPCSTR prefix
= "\\\\.\\pipe\\lrpc\\";
201 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
202 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
203 TRACE("connecting to %s\n", pname
);
205 if (WaitNamedPipeA(pname
, NMPWAIT_WAIT_FOREVER
)) {
206 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
207 OPEN_EXISTING
, 0, 0);
208 if (conn
!= INVALID_HANDLE_VALUE
) break;
209 err
= GetLastError();
210 if (err
== ERROR_PIPE_BUSY
) continue;
211 TRACE("connection failed, error=%lx\n", err
);
212 HeapFree(GetProcessHeap(), 0, pname
);
213 return RPC_S_SERVER_TOO_BUSY
;
215 err
= GetLastError();
216 WARN("connection failed, error=%lx\n", err
);
217 HeapFree(GetProcessHeap(), 0, pname
);
218 return RPC_S_SERVER_UNAVAILABLE
;
223 HeapFree(GetProcessHeap(), 0, pname
);
224 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
225 /* pipe is connected; change to message-read mode. */
226 dwMode
= PIPE_READMODE_MESSAGE
;
227 SetNamedPipeHandleState(conn
, &dwMode
, NULL
, NULL
);
228 Connection
->ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
229 Connection
->conn
= conn
;
231 /* protseq=ncacn_np: named pipes */
232 else if (strcmp(Connection
->Protseq
, "ncacn_np") == 0) {
233 static LPCSTR prefix
= "\\\\.";
239 pname
= HeapAlloc(GetProcessHeap(), 0, strlen(prefix
) + strlen(Connection
->Endpoint
) + 1);
240 strcat(strcpy(pname
, prefix
), Connection
->Endpoint
);
241 TRACE("connecting to %s\n", pname
);
242 conn
= CreateFileA(pname
, GENERIC_READ
|GENERIC_WRITE
, 0, NULL
,
243 OPEN_EXISTING
, 0, 0);
244 if (conn
== INVALID_HANDLE_VALUE
) {
245 err
= GetLastError();
246 /* we don't need to handle ERROR_PIPE_BUSY here,
247 * the doc says that it is returned to the app */
248 WARN("connection failed, error=%lx\n", err
);
249 HeapFree(GetProcessHeap(), 0, pname
);
250 if (err
== ERROR_PIPE_BUSY
)
251 return RPC_S_SERVER_TOO_BUSY
;
253 return RPC_S_SERVER_UNAVAILABLE
;
257 HeapFree(GetProcessHeap(), 0, pname
);
258 memset(&Connection
->ovl
, 0, sizeof(Connection
->ovl
));
259 /* pipe is connected; change to message-read mode. */
260 dwMode
= PIPE_READMODE_MESSAGE
;
261 SetNamedPipeHandleState(conn
, &dwMode
, NULL
, NULL
);
262 Connection
->ovl
.hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
263 Connection
->conn
= conn
;
265 ERR("protseq %s not supported\n", Connection
->Protseq
);
266 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
273 RPC_STATUS
RPCRT4_CloseConnection(RpcConnection
* Connection
)
275 TRACE("(Connection == ^%p)\n", Connection
);
276 if (Connection
->conn
) {
277 FlushFileBuffers(Connection
->conn
);
278 CloseHandle(Connection
->conn
);
279 Connection
->conn
= 0;
281 if (Connection
->ovl
.hEvent
) {
282 CloseHandle(Connection
->ovl
.hEvent
);
283 Connection
->ovl
.hEvent
= 0;
288 RPC_STATUS
RPCRT4_SpawnConnection(RpcConnection
** Connection
, RpcConnection
* OldConnection
)
290 RpcConnection
* NewConnection
;
291 RPC_STATUS err
= RPCRT4_CreateConnection(&NewConnection
, OldConnection
->server
, OldConnection
->Protseq
,
292 OldConnection
->NetworkAddr
, OldConnection
->Endpoint
, NULL
, NULL
);
293 if (err
== RPC_S_OK
) {
294 /* because of the way named pipes work, we'll transfer the connected pipe
295 * to the child, then reopen the server binding to continue listening */
296 NewConnection
->conn
= OldConnection
->conn
;
297 NewConnection
->ovl
= OldConnection
->ovl
;
298 OldConnection
->conn
= 0;
299 memset(&OldConnection
->ovl
, 0, sizeof(OldConnection
->ovl
));
300 *Connection
= NewConnection
;
301 RPCRT4_OpenConnection(OldConnection
);
306 RPC_STATUS
RPCRT4_AllocBinding(RpcBinding
** Binding
, BOOL server
)
308 RpcBinding
* NewBinding
;
310 NewBinding
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(RpcBinding
));
311 NewBinding
->refs
= 1;
312 NewBinding
->server
= server
;
314 *Binding
= NewBinding
;
319 RPC_STATUS
RPCRT4_CreateBindingA(RpcBinding
** Binding
, BOOL server
, LPSTR Protseq
)
321 RpcBinding
* NewBinding
;
323 RPCRT4_AllocBinding(&NewBinding
, server
);
324 NewBinding
->Protseq
= RPCRT4_strdupA(Protseq
);
326 TRACE("binding: %p\n", NewBinding
);
327 *Binding
= NewBinding
;
332 RPC_STATUS
RPCRT4_CreateBindingW(RpcBinding
** Binding
, BOOL server
, LPWSTR Protseq
)
334 RpcBinding
* NewBinding
;
336 RPCRT4_AllocBinding(&NewBinding
, server
);
337 NewBinding
->Protseq
= RPCRT4_strdupWtoA(Protseq
);
339 TRACE("binding: %p\n", NewBinding
);
340 *Binding
= NewBinding
;
345 RPC_STATUS
RPCRT4_CompleteBindingA(RpcBinding
* Binding
, LPSTR NetworkAddr
, LPSTR Endpoint
, LPSTR NetworkOptions
)
347 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
348 debugstr_a(NetworkAddr
), debugstr_a(Endpoint
), debugstr_a(NetworkOptions
));
350 RPCRT4_strfree(Binding
->NetworkAddr
);
351 Binding
->NetworkAddr
= RPCRT4_strdupA(NetworkAddr
);
352 RPCRT4_strfree(Binding
->Endpoint
);
354 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
356 Binding
->Endpoint
= RPCRT4_strdupA("");
358 if (!Binding
->Endpoint
) ERR("out of memory?\n");
363 RPC_STATUS
RPCRT4_CompleteBindingW(RpcBinding
* Binding
, LPWSTR NetworkAddr
, LPWSTR Endpoint
, LPWSTR NetworkOptions
)
365 TRACE("(RpcBinding == ^%p, NetworkAddr == \"%s\", EndPoint == \"%s\", NetworkOptions == \"%s\")\n", Binding
,
366 debugstr_w(NetworkAddr
), debugstr_w(Endpoint
), debugstr_w(NetworkOptions
));
368 RPCRT4_strfree(Binding
->NetworkAddr
);
369 Binding
->NetworkAddr
= RPCRT4_strdupWtoA(NetworkAddr
);
370 RPCRT4_strfree(Binding
->Endpoint
);
372 Binding
->Endpoint
= RPCRT4_strdupWtoA(Endpoint
);
374 Binding
->Endpoint
= RPCRT4_strdupA("");
376 if (!Binding
->Endpoint
) ERR("out of memory?\n");
381 RPC_STATUS
RPCRT4_ResolveBinding(RpcBinding
* Binding
, LPSTR Endpoint
)
383 TRACE("(RpcBinding == ^%p, EndPoint == \"%s\"\n", Binding
, Endpoint
);
385 RPCRT4_strfree(Binding
->Endpoint
);
386 Binding
->Endpoint
= RPCRT4_strdupA(Endpoint
);
391 RPC_STATUS
RPCRT4_SetBindingObject(RpcBinding
* Binding
, UUID
* ObjectUuid
)
393 TRACE("(*RpcBinding == ^%p, UUID == %s)\n", Binding
, debugstr_guid(ObjectUuid
));
394 if (ObjectUuid
) memcpy(&Binding
->ObjectUuid
, ObjectUuid
, sizeof(UUID
));
395 else UuidCreateNil(&Binding
->ObjectUuid
);
399 RPC_STATUS
RPCRT4_MakeBinding(RpcBinding
** Binding
, RpcConnection
* Connection
)
401 RpcBinding
* NewBinding
;
402 TRACE("(RpcBinding == ^%p, Connection == ^%p)\n", Binding
, Connection
);
404 RPCRT4_AllocBinding(&NewBinding
, Connection
->server
);
405 NewBinding
->Protseq
= RPCRT4_strdupA(Connection
->Protseq
);
406 NewBinding
->NetworkAddr
= RPCRT4_strdupA(Connection
->NetworkAddr
);
407 NewBinding
->Endpoint
= RPCRT4_strdupA(Connection
->Endpoint
);
408 NewBinding
->FromConn
= Connection
;
410 TRACE("binding: %p\n", NewBinding
);
411 *Binding
= NewBinding
;
416 RPC_STATUS
RPCRT4_ExportBinding(RpcBinding
** Binding
, RpcBinding
* OldBinding
)
418 InterlockedIncrement(&OldBinding
->refs
);
419 *Binding
= OldBinding
;
423 RPC_STATUS
RPCRT4_DestroyBinding(RpcBinding
* Binding
)
425 if (InterlockedDecrement(&Binding
->refs
))
428 TRACE("binding: %p\n", Binding
);
429 /* FIXME: release connections */
430 RPCRT4_strfree(Binding
->Endpoint
);
431 RPCRT4_strfree(Binding
->NetworkAddr
);
432 RPCRT4_strfree(Binding
->Protseq
);
433 HeapFree(GetProcessHeap(), 0, Binding
);
437 RPC_STATUS
RPCRT4_OpenBinding(RpcBinding
* Binding
, RpcConnection
** Connection
,
438 PRPC_SYNTAX_IDENTIFIER TransferSyntax
,
439 PRPC_SYNTAX_IDENTIFIER InterfaceId
)
441 RpcConnection
* NewConnection
;
444 TRACE("(Binding == ^%p)\n", Binding
);
446 /* if we try to bind a new interface and the connection is already opened,
447 * close the current connection and create a new with the new binding. */
448 if (!Binding
->server
&& Binding
->FromConn
&&
449 memcmp(&Binding
->FromConn
->ActiveInterface
, InterfaceId
,
450 sizeof(RPC_SYNTAX_IDENTIFIER
))) {
452 TRACE("releasing pre-existing connection\n");
453 RPCRT4_DestroyConnection(Binding
->FromConn
);
454 Binding
->FromConn
= NULL
;
456 /* we already have a connection with acceptable binding, so use it */
457 if (Binding
->FromConn
) {
458 *Connection
= Binding
->FromConn
;
463 /* create a new connection */
464 RPCRT4_CreateConnection(&NewConnection
, Binding
->server
, Binding
->Protseq
, Binding
->NetworkAddr
, Binding
->Endpoint
, NULL
, Binding
);
465 *Connection
= NewConnection
;
466 status
= RPCRT4_OpenConnection(NewConnection
);
467 if (status
!= RPC_S_OK
) {
471 /* we need to send a binding packet if we are client. */
472 if (!(*Connection
)->server
) {
476 RpcPktHdr
*response_hdr
;
478 TRACE("sending bind request to server\n");
480 hdr
= RPCRT4_BuildBindHeader(NDR_LOCAL_DATA_REPRESENTATION
,
481 RPC_MAX_PACKET_SIZE
, RPC_MAX_PACKET_SIZE
,
482 InterfaceId
, TransferSyntax
);
484 status
= RPCRT4_Send(*Connection
, hdr
, NULL
, 0);
485 if (status
!= RPC_S_OK
) {
486 RPCRT4_DestroyConnection(*Connection
);
490 response
= HeapAlloc(GetProcessHeap(), 0, RPC_MAX_PACKET_SIZE
);
491 if (response
== NULL
) {
492 WARN("Can't allocate memory for binding response\n");
493 RPCRT4_DestroyConnection(*Connection
);
494 return E_OUTOFMEMORY
;
498 if (!ReadFile(NewConnection
->conn
, response
, RPC_MAX_PACKET_SIZE
, &count
, NULL
)) {
499 WARN("ReadFile failed with error %ld\n", GetLastError());
500 RPCRT4_DestroyConnection(*Connection
);
501 return RPC_S_PROTOCOL_ERROR
;
504 if (count
< sizeof(response_hdr
->common
)) {
505 WARN("received invalid header\n");
506 RPCRT4_DestroyConnection(*Connection
);
507 return RPC_S_PROTOCOL_ERROR
;
510 response_hdr
= (RpcPktHdr
*)response
;
512 if (response_hdr
->common
.rpc_ver
!= RPC_VER_MAJOR
||
513 response_hdr
->common
.rpc_ver_minor
!= RPC_VER_MINOR
||
514 response_hdr
->common
.ptype
!= PKT_BIND_ACK
) {
515 WARN("invalid protocol version or rejection packet\n");
516 RPCRT4_DestroyConnection(*Connection
);
517 return RPC_S_PROTOCOL_ERROR
;
520 if (response_hdr
->bind_ack
.max_tsize
< RPC_MIN_PACKET_SIZE
) {
521 WARN("server doesn't allow large enough packets\n");
522 RPCRT4_DestroyConnection(*Connection
);
523 return RPC_S_PROTOCOL_ERROR
;
526 /* FIXME: do more checks? */
528 (*Connection
)->MaxTransmissionSize
= response_hdr
->bind_ack
.max_tsize
;
529 (*Connection
)->ActiveInterface
= *InterfaceId
;
535 RPC_STATUS
RPCRT4_CloseBinding(RpcBinding
* Binding
, RpcConnection
* Connection
)
537 TRACE("(Binding == ^%p)\n", Binding
);
538 if (!Connection
) return RPC_S_OK
;
539 if (Binding
->FromConn
== Connection
) return RPC_S_OK
;
540 return RPCRT4_DestroyConnection(Connection
);
543 /* utility functions for string composing and parsing */
544 static unsigned RPCRT4_strcopyA(LPSTR data
, LPCSTR src
)
546 unsigned len
= strlen(src
);
547 memcpy(data
, src
, len
*sizeof(CHAR
));
551 static unsigned RPCRT4_strcopyW(LPWSTR data
, LPCWSTR src
)
553 unsigned len
= strlenW(src
);
554 memcpy(data
, src
, len
*sizeof(WCHAR
));
558 static LPSTR
RPCRT4_strconcatA(LPSTR dst
, LPCSTR src
)
560 DWORD len
= strlen(dst
), slen
= strlen(src
);
561 LPSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(CHAR
));
564 HeapFree(GetProcessHeap(), 0, dst
);
568 memcpy(ndst
+len
+1, src
, slen
+1);
572 static LPWSTR
RPCRT4_strconcatW(LPWSTR dst
, LPCWSTR src
)
574 DWORD len
= strlenW(dst
), slen
= strlenW(src
);
575 LPWSTR ndst
= HeapReAlloc(GetProcessHeap(), 0, dst
, (len
+slen
+2)*sizeof(WCHAR
));
578 HeapFree(GetProcessHeap(), 0, dst
);
582 memcpy(ndst
+len
+1, src
, (slen
+1)*sizeof(WCHAR
));
587 /***********************************************************************
588 * RpcStringBindingComposeA (RPCRT4.@)
590 RPC_STATUS WINAPI
RpcStringBindingComposeA(unsigned char *ObjUuid
, unsigned char *Protseq
,
591 unsigned char *NetworkAddr
, unsigned char *Endpoint
,
592 unsigned char *Options
, unsigned char** StringBinding
)
597 TRACE( "(%s,%s,%s,%s,%s,%p)\n",
598 debugstr_a( ObjUuid
), debugstr_a( Protseq
),
599 debugstr_a( NetworkAddr
), debugstr_a( Endpoint
),
600 debugstr_a( Options
), StringBinding
);
602 if (ObjUuid
&& *ObjUuid
) len
+= strlen(ObjUuid
) + 1;
603 if (Protseq
&& *Protseq
) len
+= strlen(Protseq
) + 1;
604 if (NetworkAddr
&& *NetworkAddr
) len
+= strlen(NetworkAddr
);
605 if (Endpoint
&& *Endpoint
) len
+= strlen(Endpoint
) + 2;
606 if (Options
&& *Options
) len
+= strlen(Options
) + 2;
608 data
= HeapAlloc(GetProcessHeap(), 0, len
);
609 *StringBinding
= data
;
611 if (ObjUuid
&& *ObjUuid
) {
612 data
+= RPCRT4_strcopyA(data
, ObjUuid
);
615 if (Protseq
&& *Protseq
) {
616 data
+= RPCRT4_strcopyA(data
, Protseq
);
619 if (NetworkAddr
&& *NetworkAddr
)
620 data
+= RPCRT4_strcopyA(data
, NetworkAddr
);
622 if ((Endpoint
&& *Endpoint
) ||
623 (Options
&& *Options
)) {
625 if (Endpoint
&& *Endpoint
) {
626 data
+= RPCRT4_strcopyA(data
, Endpoint
);
627 if (Options
&& *Options
) *data
++ = ',';
629 if (Options
&& *Options
) {
630 data
+= RPCRT4_strcopyA(data
, Options
);
639 /***********************************************************************
640 * RpcStringBindingComposeW (RPCRT4.@)
642 RPC_STATUS WINAPI
RpcStringBindingComposeW( LPWSTR ObjUuid
, LPWSTR Protseq
,
643 LPWSTR NetworkAddr
, LPWSTR Endpoint
,
644 LPWSTR Options
, LPWSTR
* StringBinding
)
649 TRACE("(%s,%s,%s,%s,%s,%p)\n",
650 debugstr_w( ObjUuid
), debugstr_w( Protseq
),
651 debugstr_w( NetworkAddr
), debugstr_w( Endpoint
),
652 debugstr_w( Options
), StringBinding
);
654 if (ObjUuid
&& *ObjUuid
) len
+= strlenW(ObjUuid
) + 1;
655 if (Protseq
&& *Protseq
) len
+= strlenW(Protseq
) + 1;
656 if (NetworkAddr
&& *NetworkAddr
) len
+= strlenW(NetworkAddr
);
657 if (Endpoint
&& *Endpoint
) len
+= strlenW(Endpoint
) + 2;
658 if (Options
&& *Options
) len
+= strlenW(Options
) + 2;
660 data
= HeapAlloc(GetProcessHeap(), 0, len
*sizeof(WCHAR
));
661 *StringBinding
= data
;
663 if (ObjUuid
&& *ObjUuid
) {
664 data
+= RPCRT4_strcopyW(data
, ObjUuid
);
667 if (Protseq
&& *Protseq
) {
668 data
+= RPCRT4_strcopyW(data
, Protseq
);
671 if (NetworkAddr
&& *NetworkAddr
) {
672 data
+= RPCRT4_strcopyW(data
, NetworkAddr
);
674 if ((Endpoint
&& *Endpoint
) ||
675 (Options
&& *Options
)) {
677 if (Endpoint
&& *Endpoint
) {
678 data
+= RPCRT4_strcopyW(data
, Endpoint
);
679 if (Options
&& *Options
) *data
++ = ',';
681 if (Options
&& *Options
) {
682 data
+= RPCRT4_strcopyW(data
, Options
);
692 /***********************************************************************
693 * RpcStringBindingParseA (RPCRT4.@)
695 RPC_STATUS WINAPI
RpcStringBindingParseA( unsigned char *StringBinding
, unsigned char **ObjUuid
,
696 unsigned char **Protseq
, unsigned char **NetworkAddr
,
697 unsigned char **Endpoint
, unsigned char **Options
)
700 static const char ep_opt
[] = "endpoint=";
702 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_a(StringBinding
),
703 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
705 if (ObjUuid
) *ObjUuid
= NULL
;
706 if (Protseq
) *Protseq
= NULL
;
707 if (NetworkAddr
) *NetworkAddr
= NULL
;
708 if (Endpoint
) *Endpoint
= NULL
;
709 if (Options
) *Options
= NULL
;
711 data
= StringBinding
;
713 next
= strchr(data
, '@');
715 if (ObjUuid
) *ObjUuid
= RPCRT4_strndupA(data
, next
- data
);
719 next
= strchr(data
, ':');
721 if (Protseq
) *Protseq
= RPCRT4_strndupA(data
, next
- data
);
725 next
= strchr(data
, '[');
729 if (NetworkAddr
) *NetworkAddr
= RPCRT4_strndupA(data
, next
- data
);
731 close
= strchr(data
, ']');
732 if (!close
) goto fail
;
734 /* tokenize options */
735 while (data
< close
) {
736 next
= strchr(data
, ',');
737 if (!next
|| next
> close
) next
= close
;
738 /* FIXME: this is kind of inefficient */
739 opt
= RPCRT4_strndupA(data
, next
- data
);
743 next
= strchr(opt
, '=');
745 /* not an option, must be an endpoint */
746 if (*Endpoint
) goto fail
;
749 if (strncmp(opt
, ep_opt
, strlen(ep_opt
)) == 0) {
750 /* endpoint option */
751 if (*Endpoint
) goto fail
;
752 *Endpoint
= RPCRT4_strdupA(next
+1);
753 HeapFree(GetProcessHeap(), 0, opt
);
757 /* FIXME: this is kind of inefficient */
758 *Options
= RPCRT4_strconcatA(*Options
, opt
);
759 HeapFree(GetProcessHeap(), 0, opt
);
767 if (*data
) goto fail
;
769 else if (NetworkAddr
)
770 *NetworkAddr
= RPCRT4_strdupA(data
);
775 if (ObjUuid
) RpcStringFreeA((unsigned char**)ObjUuid
);
776 if (Protseq
) RpcStringFreeA((unsigned char**)Protseq
);
777 if (NetworkAddr
) RpcStringFreeA((unsigned char**)NetworkAddr
);
778 if (Endpoint
) RpcStringFreeA((unsigned char**)Endpoint
);
779 if (Options
) RpcStringFreeA((unsigned char**)Options
);
780 return RPC_S_INVALID_STRING_BINDING
;
783 /***********************************************************************
784 * RpcStringBindingParseW (RPCRT4.@)
786 RPC_STATUS WINAPI
RpcStringBindingParseW( LPWSTR StringBinding
, LPWSTR
*ObjUuid
,
787 LPWSTR
*Protseq
, LPWSTR
*NetworkAddr
,
788 LPWSTR
*Endpoint
, LPWSTR
*Options
)
791 static const WCHAR ep_opt
[] = {'e','n','d','p','o','i','n','t','=',0};
793 TRACE("(%s,%p,%p,%p,%p,%p)\n", debugstr_w(StringBinding
),
794 ObjUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
);
796 if (ObjUuid
) *ObjUuid
= NULL
;
797 if (Protseq
) *Protseq
= NULL
;
798 if (NetworkAddr
) *NetworkAddr
= NULL
;
799 if (Endpoint
) *Endpoint
= NULL
;
800 if (Options
) *Options
= NULL
;
802 data
= StringBinding
;
804 next
= strchrW(data
, '@');
806 if (ObjUuid
) *ObjUuid
= RPCRT4_strndupW(data
, next
- data
);
810 next
= strchrW(data
, ':');
812 if (Protseq
) *Protseq
= RPCRT4_strndupW(data
, next
- data
);
816 next
= strchrW(data
, '[');
820 if (NetworkAddr
) *NetworkAddr
= RPCRT4_strndupW(data
, next
- data
);
822 close
= strchrW(data
, ']');
823 if (!close
) goto fail
;
825 /* tokenize options */
826 while (data
< close
) {
827 next
= strchrW(data
, ',');
828 if (!next
|| next
> close
) next
= close
;
829 /* FIXME: this is kind of inefficient */
830 opt
= RPCRT4_strndupW(data
, next
- data
);
834 next
= strchrW(opt
, '=');
836 /* not an option, must be an endpoint */
837 if (*Endpoint
) goto fail
;
840 if (strncmpW(opt
, ep_opt
, strlenW(ep_opt
)) == 0) {
841 /* endpoint option */
842 if (*Endpoint
) goto fail
;
843 *Endpoint
= RPCRT4_strdupW(next
+1);
844 HeapFree(GetProcessHeap(), 0, opt
);
848 /* FIXME: this is kind of inefficient */
849 *Options
= RPCRT4_strconcatW(*Options
, opt
);
850 HeapFree(GetProcessHeap(), 0, opt
);
858 if (*data
) goto fail
;
859 } else if (NetworkAddr
)
860 *NetworkAddr
= RPCRT4_strdupW(data
);
865 if (ObjUuid
) RpcStringFreeW(ObjUuid
);
866 if (Protseq
) RpcStringFreeW(Protseq
);
867 if (NetworkAddr
) RpcStringFreeW(NetworkAddr
);
868 if (Endpoint
) RpcStringFreeW(Endpoint
);
869 if (Options
) RpcStringFreeW(Options
);
870 return RPC_S_INVALID_STRING_BINDING
;
873 /***********************************************************************
874 * RpcBindingFree (RPCRT4.@)
876 RPC_STATUS WINAPI
RpcBindingFree( RPC_BINDING_HANDLE
* Binding
)
879 TRACE("(%p) = %p\n", Binding
, *Binding
);
880 status
= RPCRT4_DestroyBinding(*Binding
);
881 if (status
== RPC_S_OK
) *Binding
= 0;
885 /***********************************************************************
886 * RpcBindingVectorFree (RPCRT4.@)
888 RPC_STATUS WINAPI
RpcBindingVectorFree( RPC_BINDING_VECTOR
** BindingVector
)
893 TRACE("(%p)\n", BindingVector
);
894 for (c
=0; c
<(*BindingVector
)->Count
; c
++) {
895 status
= RpcBindingFree(&(*BindingVector
)->BindingH
[c
]);
897 HeapFree(GetProcessHeap(), 0, *BindingVector
);
898 *BindingVector
= NULL
;
902 /***********************************************************************
903 * RpcBindingInqObject (RPCRT4.@)
905 RPC_STATUS WINAPI
RpcBindingInqObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
907 RpcBinding
* bind
= (RpcBinding
*)Binding
;
909 TRACE("(%p,%p) = %s\n", Binding
, ObjectUuid
, debugstr_guid(&bind
->ObjectUuid
));
910 memcpy(ObjectUuid
, &bind
->ObjectUuid
, sizeof(UUID
));
914 /***********************************************************************
915 * RpcBindingSetObject (RPCRT4.@)
917 RPC_STATUS WINAPI
RpcBindingSetObject( RPC_BINDING_HANDLE Binding
, UUID
* ObjectUuid
)
919 RpcBinding
* bind
= (RpcBinding
*)Binding
;
921 TRACE("(%p,%s)\n", Binding
, debugstr_guid(ObjectUuid
));
922 if (bind
->server
) return RPC_S_WRONG_KIND_OF_BINDING
;
923 return RPCRT4_SetBindingObject(Binding
, ObjectUuid
);
926 /***********************************************************************
927 * RpcBindingFromStringBindingA (RPCRT4.@)
929 RPC_STATUS WINAPI
RpcBindingFromStringBindingA( unsigned char *StringBinding
, RPC_BINDING_HANDLE
* Binding
)
932 RpcBinding
* bind
= NULL
;
933 unsigned char *ObjectUuid
, *Protseq
, *NetworkAddr
, *Endpoint
, *Options
;
936 TRACE("(%s,%p)\n", debugstr_a(StringBinding
), Binding
);
938 ret
= RpcStringBindingParseA(StringBinding
, &ObjectUuid
, &Protseq
,
939 &NetworkAddr
, &Endpoint
, &Options
);
940 if (ret
!= RPC_S_OK
) return ret
;
942 ret
= UuidFromStringA(ObjectUuid
, &Uuid
);
945 ret
= RPCRT4_CreateBindingA(&bind
, FALSE
, Protseq
);
947 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
949 ret
= RPCRT4_CompleteBindingA(bind
, NetworkAddr
, Endpoint
, Options
);
951 RpcStringFreeA((unsigned char**)&Options
);
952 RpcStringFreeA((unsigned char**)&Endpoint
);
953 RpcStringFreeA((unsigned char**)&NetworkAddr
);
954 RpcStringFreeA((unsigned char**)&Protseq
);
955 RpcStringFreeA((unsigned char**)&ObjectUuid
);
958 *Binding
= (RPC_BINDING_HANDLE
)bind
;
960 RPCRT4_DestroyBinding(bind
);
965 /***********************************************************************
966 * RpcBindingFromStringBindingW (RPCRT4.@)
968 RPC_STATUS WINAPI
RpcBindingFromStringBindingW( LPWSTR StringBinding
, RPC_BINDING_HANDLE
* Binding
)
971 RpcBinding
* bind
= NULL
;
972 LPWSTR ObjectUuid
, Protseq
, NetworkAddr
, Endpoint
, Options
;
975 TRACE("(%s,%p)\n", debugstr_w(StringBinding
), Binding
);
977 ret
= RpcStringBindingParseW(StringBinding
, &ObjectUuid
, &Protseq
,
978 &NetworkAddr
, &Endpoint
, &Options
);
979 if (ret
!= RPC_S_OK
) return ret
;
981 ret
= UuidFromStringW(ObjectUuid
, &Uuid
);
984 ret
= RPCRT4_CreateBindingW(&bind
, FALSE
, Protseq
);
986 ret
= RPCRT4_SetBindingObject(bind
, &Uuid
);
988 ret
= RPCRT4_CompleteBindingW(bind
, NetworkAddr
, Endpoint
, Options
);
990 RpcStringFreeW(&Options
);
991 RpcStringFreeW(&Endpoint
);
992 RpcStringFreeW(&NetworkAddr
);
993 RpcStringFreeW(&Protseq
);
994 RpcStringFreeW(&ObjectUuid
);
997 *Binding
= (RPC_BINDING_HANDLE
)bind
;
999 RPCRT4_DestroyBinding(bind
);
1004 /***********************************************************************
1005 * RpcBindingToStringBindingA (RPCRT4.@)
1007 RPC_STATUS WINAPI
RpcBindingToStringBindingA( RPC_BINDING_HANDLE Binding
, unsigned char** StringBinding
)
1010 RpcBinding
* bind
= (RpcBinding
*)Binding
;
1013 TRACE("(%p,%p)\n", Binding
, StringBinding
);
1015 ret
= UuidToStringA(&bind
->ObjectUuid
, (unsigned char**)&ObjectUuid
);
1016 if (ret
!= RPC_S_OK
) return ret
;
1018 ret
= RpcStringBindingComposeA(ObjectUuid
, bind
->Protseq
, bind
->NetworkAddr
,
1019 bind
->Endpoint
, NULL
, StringBinding
);
1021 RpcStringFreeA((unsigned char**)&ObjectUuid
);
1026 /***********************************************************************
1027 * RpcBindingToStringBindingW (RPCRT4.@)
1029 RPC_STATUS WINAPI
RpcBindingToStringBindingW( RPC_BINDING_HANDLE Binding
, unsigned short** StringBinding
)
1032 unsigned char *str
= NULL
;
1033 TRACE("(%p,%p)\n", Binding
, StringBinding
);
1034 ret
= RpcBindingToStringBindingA(Binding
, &str
);
1035 *StringBinding
= RPCRT4_strdupAtoW(str
);
1036 RpcStringFreeA((unsigned char**)&str
);
1040 /***********************************************************************
1041 * I_RpcBindingSetAsync (RPCRT4.@)
1043 * Exists in win9x and winNT, but with different number of arguments
1044 * (9x version has 3 arguments, NT has 2).
1046 RPC_STATUS WINAPI
I_RpcBindingSetAsync( RPC_BINDING_HANDLE Binding
, RPC_BLOCKING_FN BlockingFn
)
1048 RpcBinding
* bind
= (RpcBinding
*)Binding
;
1050 TRACE( "(%p,%p): stub\n", Binding
, BlockingFn
);
1052 bind
->BlockingFn
= BlockingFn
;
1057 /***********************************************************************
1058 * RpcNetworkIsProtseqValidA (RPCRT4.@)
1060 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidA(unsigned char *protseq
) {
1061 UNICODE_STRING protseqW
;
1063 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1065 if (RtlCreateUnicodeStringFromAsciiz(&protseqW
, protseq
)) {
1066 RPC_STATUS ret
= RpcNetworkIsProtseqValidW(protseqW
.Buffer
);
1067 RtlFreeUnicodeString(&protseqW
);
1069 } else return RPC_S_OUT_OF_MEMORY
;
1072 /***********************************************************************
1073 * RpcNetworkIsProtseqValidW (RPCRT4.@)
1075 * Checks if the given protocol sequence is known by the RPC system.
1076 * If it is, returns RPC_S_OK, otherwise RPC_S_PROTSEQ_NOT_SUPPORTED.
1078 * We currently support:
1079 * ncalrpc local-only rpc over LPC (LPC is not really used)
1080 * ncacn_np rpc over named pipes
1082 RPC_STATUS WINAPI
RpcNetworkIsProtseqValidW(LPWSTR protseq
) {
1083 static const WCHAR protseqsW
[][15] = {
1084 {'n','c','a','l','r','p','c',0},
1085 {'n','c','a','c','n','_','n','p',0}
1087 static const int count
= sizeof(protseqsW
) / sizeof(protseqsW
[0]);
1090 if (!protseq
) return RPC_S_INVALID_RPC_PROTSEQ
; /* ? */
1092 for (i
= 0; i
< count
; i
++) {
1093 if (!strcmpW(protseq
, protseqsW
[i
])) return RPC_S_OK
;
1096 FIXME("Unknown protseq %s - we probably need to implement it one day\n", debugstr_w(protseq
));
1097 return RPC_S_PROTSEQ_NOT_SUPPORTED
;
1100 /***********************************************************************
1101 * RpcImpersonateClient (RPCRT4.@)
1103 * Impersonates the client connected via a binding handle so that security
1104 * checks are done in the context of the client.
1107 * BindingHandle [I] Handle to the binding to the client.
1110 * Success: RPS_S_OK.
1111 * Failure: RPC_STATUS value.
1115 * If BindingHandle is NULL then the function impersonates the client
1116 * connected to the binding handle of the current thread.
1118 RPC_STATUS WINAPI
RpcImpersonateClient(RPC_BINDING_HANDLE BindingHandle
)
1120 FIXME("(%p): stub\n", BindingHandle
);
1124 /***********************************************************************
1125 * RpcRevertToSelfEx (RPCRT4.@)
1127 * Stops impersonating the client connected to the binding handle so that security
1128 * checks are no longer done in the context of the client.
1131 * BindingHandle [I] Handle to the binding to the client.
1134 * Success: RPS_S_OK.
1135 * Failure: RPC_STATUS value.
1139 * If BindingHandle is NULL then the function stops impersonating the client
1140 * connected to the binding handle of the current thread.
1142 RPC_STATUS WINAPI
RpcRevertToSelfEx(RPC_BINDING_HANDLE BindingHandle
)
1144 FIXME("(%p): stub\n", BindingHandle
);